mirror of
https://github.com/ZwareBear/awx.git
synced 2026-03-20 07:43:35 -05:00
Merge branch 'devel' into ui_next
This commit is contained in:
1
.github/workflows/promote.yml
vendored
1
.github/workflows/promote.yml
vendored
@@ -10,6 +10,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
promote:
|
promote:
|
||||||
|
if: endsWith(github.repository, '/awx')
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout awx
|
- name: Checkout awx
|
||||||
|
|||||||
1
.github/workflows/stage.yml
vendored
1
.github/workflows/stage.yml
vendored
@@ -21,6 +21,7 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
stage:
|
stage:
|
||||||
|
if: endsWith(github.repository, '/awx')
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
packages: write
|
packages: write
|
||||||
|
|||||||
14
Makefile
14
Makefile
@@ -205,19 +205,7 @@ uwsgi: collectstatic
|
|||||||
@if [ "$(VENV_BASE)" ]; then \
|
@if [ "$(VENV_BASE)" ]; then \
|
||||||
. $(VENV_BASE)/awx/bin/activate; \
|
. $(VENV_BASE)/awx/bin/activate; \
|
||||||
fi; \
|
fi; \
|
||||||
uwsgi -b 32768 \
|
uwsgi /etc/tower/uwsgi.ini
|
||||||
--socket 127.0.0.1:8050 \
|
|
||||||
--module=awx.wsgi:application \
|
|
||||||
--home=/var/lib/awx/venv/awx \
|
|
||||||
--chdir=/awx_devel/ \
|
|
||||||
--vacuum \
|
|
||||||
--processes=5 \
|
|
||||||
--harakiri=120 --master \
|
|
||||||
--no-orphans \
|
|
||||||
--max-requests=1000 \
|
|
||||||
--stats /tmp/stats.socket \
|
|
||||||
--lazy-apps \
|
|
||||||
--logformat "%(addr) %(method) %(uri) - %(proto) %(status)"
|
|
||||||
|
|
||||||
awx-autoreload:
|
awx-autoreload:
|
||||||
@/awx_devel/tools/docker-compose/awx-autoreload /awx_devel/awx "$(DEV_RELOAD_COMMAND)"
|
@/awx_devel/tools/docker-compose/awx-autoreload /awx_devel/awx "$(DEV_RELOAD_COMMAND)"
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ from rest_framework import generics
|
|||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework import views
|
from rest_framework import views
|
||||||
from rest_framework.permissions import AllowAny
|
from rest_framework.permissions import IsAuthenticated
|
||||||
from rest_framework.renderers import StaticHTMLRenderer
|
from rest_framework.renderers import StaticHTMLRenderer
|
||||||
from rest_framework.negotiation import DefaultContentNegotiation
|
from rest_framework.negotiation import DefaultContentNegotiation
|
||||||
|
|
||||||
@@ -822,7 +822,7 @@ def trigger_delayed_deep_copy(*args, **kwargs):
|
|||||||
|
|
||||||
class CopyAPIView(GenericAPIView):
|
class CopyAPIView(GenericAPIView):
|
||||||
serializer_class = CopySerializer
|
serializer_class = CopySerializer
|
||||||
permission_classes = (AllowAny,)
|
permission_classes = (IsAuthenticated,)
|
||||||
copy_return_serializer_class = None
|
copy_return_serializer_class = None
|
||||||
new_in_330 = True
|
new_in_330 = True
|
||||||
new_in_api_v2 = True
|
new_in_api_v2 = True
|
||||||
|
|||||||
@@ -4288,7 +4288,7 @@ class WorkflowApprovalTemplateJobsList(SubListAPIView):
|
|||||||
parent_key = 'workflow_approval_template'
|
parent_key = 'workflow_approval_template'
|
||||||
|
|
||||||
|
|
||||||
class WorkflowApprovalList(ListCreateAPIView):
|
class WorkflowApprovalList(ListAPIView):
|
||||||
model = models.WorkflowApproval
|
model = models.WorkflowApproval
|
||||||
serializer_class = serializers.WorkflowApprovalListSerializer
|
serializer_class = serializers.WorkflowApprovalListSerializer
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ class AWXProtocolTypeRouter(ProtocolTypeRouter):
|
|||||||
|
|
||||||
|
|
||||||
websocket_urlpatterns = [
|
websocket_urlpatterns = [
|
||||||
re_path(r'websocket/$', consumers.EventConsumer.as_asgi()),
|
re_path(r'websocket/', consumers.EventConsumer.as_asgi()),
|
||||||
re_path(r'websocket/broadcast/$', consumers.BroadcastConsumer.as_asgi()),
|
re_path(r'websocket/broadcast/', consumers.BroadcastConsumer.as_asgi()),
|
||||||
]
|
]
|
||||||
|
|
||||||
application = AWXProtocolTypeRouter(
|
application = AWXProtocolTypeRouter(
|
||||||
|
|||||||
@@ -311,7 +311,7 @@ class BaseTask(object):
|
|||||||
env['AWX_PRIVATE_DATA_DIR'] = private_data_dir
|
env['AWX_PRIVATE_DATA_DIR'] = private_data_dir
|
||||||
|
|
||||||
if self.instance.execution_environment is None:
|
if self.instance.execution_environment is None:
|
||||||
raise RuntimeError('The project could not sync because there is no Execution Environment.')
|
raise RuntimeError(f'The {self.model.__name__} could not run because there is no Execution Environment.')
|
||||||
|
|
||||||
return env
|
return env
|
||||||
|
|
||||||
|
|||||||
@@ -2008,7 +2008,7 @@ def test_project_update_no_ee(mock_me):
|
|||||||
with pytest.raises(RuntimeError) as e:
|
with pytest.raises(RuntimeError) as e:
|
||||||
task.build_env(job, {})
|
task.build_env(job, {})
|
||||||
|
|
||||||
assert 'The project could not sync because there is no Execution Environment' in str(e.value)
|
assert 'The ProjectUpdate could not run because there is no Execution Environment' in str(e.value)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import os
|
import os
|
||||||
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@@ -6,8 +7,15 @@ from django.conf import settings
|
|||||||
from awx.main.models.execution_environments import ExecutionEnvironment
|
from awx.main.models.execution_environments import ExecutionEnvironment
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def get_control_plane_execution_environment():
|
def get_control_plane_execution_environment():
|
||||||
return ExecutionEnvironment.objects.filter(organization=None, managed=True).first()
|
ee = ExecutionEnvironment.objects.filter(organization=None, managed=True).first()
|
||||||
|
if ee == None:
|
||||||
|
logger.error('Failed to find control plane ee, there are no managed EEs without organizations')
|
||||||
|
raise RuntimeError("Failed to find default control plane EE")
|
||||||
|
return ee
|
||||||
|
|
||||||
|
|
||||||
def get_default_execution_environment():
|
def get_default_execution_environment():
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ class LookupModule(LookupBase):
|
|||||||
if isinstance(rule[field_name], int):
|
if isinstance(rule[field_name], int):
|
||||||
rule[field_name] = [rule[field_name]]
|
rule[field_name] = [rule[field_name]]
|
||||||
# If its not a list, we need to split it into a list
|
# If its not a list, we need to split it into a list
|
||||||
if isinstance(rule[field_name], list):
|
if not isinstance(rule[field_name], list):
|
||||||
rule[field_name] = rule[field_name].split(',')
|
rule[field_name] = rule[field_name].split(',')
|
||||||
for value in rule[field_name]:
|
for value in rule[field_name]:
|
||||||
# If they have a list of strs we want to strip the str incase its space delineated
|
# If they have a list of strs we want to strip the str incase its space delineated
|
||||||
@@ -210,7 +210,8 @@ class LookupModule(LookupBase):
|
|||||||
|
|
||||||
def process_list(self, field_name, rule, valid_list, rule_number):
|
def process_list(self, field_name, rule, valid_list, rule_number):
|
||||||
return_values = []
|
return_values = []
|
||||||
if isinstance(rule[field_name], list):
|
# If its not a list, we need to split it into a list
|
||||||
|
if not isinstance(rule[field_name], list):
|
||||||
rule[field_name] = rule[field_name].split(',')
|
rule[field_name] = rule[field_name].split(',')
|
||||||
for value in rule[field_name]:
|
for value in rule[field_name]:
|
||||||
value = value.strip()
|
value = value.strip()
|
||||||
|
|||||||
@@ -57,7 +57,15 @@ extends_documentation_fragment: awx.awx.auth
|
|||||||
|
|
||||||
|
|
||||||
EXAMPLES = """
|
EXAMPLES = """
|
||||||
- name: Launch a workflow with a timeout of 10 seconds
|
- name: Create a workflow approval node
|
||||||
|
workflow_job_template_node:
|
||||||
|
identifier: approval_test
|
||||||
|
approval_node:
|
||||||
|
name: approval_jt_name
|
||||||
|
timeout: 900
|
||||||
|
workflow: "Test Workflow"
|
||||||
|
|
||||||
|
- name: Launch the workflow with a timeout of 10 seconds
|
||||||
workflow_launch:
|
workflow_launch:
|
||||||
workflow_template: "Test Workflow"
|
workflow_template: "Test Workflow"
|
||||||
wait: False
|
wait: False
|
||||||
@@ -66,7 +74,7 @@ EXAMPLES = """
|
|||||||
- name: Wait for approval node to activate and approve
|
- name: Wait for approval node to activate and approve
|
||||||
workflow_approval:
|
workflow_approval:
|
||||||
workflow_job_id: "{{ workflow.id }}"
|
workflow_job_id: "{{ workflow.id }}"
|
||||||
name: Approve Me
|
name: approval_jt_name
|
||||||
interval: 10
|
interval: 10
|
||||||
timeout: 20
|
timeout: 20
|
||||||
action: deny
|
action: deny
|
||||||
|
|||||||
@@ -183,7 +183,21 @@ options:
|
|||||||
inventory:
|
inventory:
|
||||||
description:
|
description:
|
||||||
- Inventory applied as a prompt, if job template prompts for inventory
|
- Inventory applied as a prompt, if job template prompts for inventory
|
||||||
type: str
|
type: dict
|
||||||
|
suboptions:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- Name Inventory to be applied to job as launch-time prompts.
|
||||||
|
type: str
|
||||||
|
organization:
|
||||||
|
description:
|
||||||
|
- Name of key for use in model for organizational reference
|
||||||
|
type: dict
|
||||||
|
suboptions:
|
||||||
|
name:
|
||||||
|
description:
|
||||||
|
- The organization of the credentials exists in.
|
||||||
|
type: str
|
||||||
scm_branch:
|
scm_branch:
|
||||||
description:
|
description:
|
||||||
- SCM branch applied as a prompt, if job template prompts for SCM branch
|
- SCM branch applied as a prompt, if job template prompts for SCM branch
|
||||||
@@ -544,6 +558,10 @@ EXAMPLES = '''
|
|||||||
type: job_template
|
type: job_template
|
||||||
execution_environment:
|
execution_environment:
|
||||||
name: My EE
|
name: My EE
|
||||||
|
inventory:
|
||||||
|
name: Test inventory
|
||||||
|
organization:
|
||||||
|
name: Default
|
||||||
related:
|
related:
|
||||||
credentials:
|
credentials:
|
||||||
- name: cyberark
|
- name: cyberark
|
||||||
@@ -613,10 +631,6 @@ def create_workflow_nodes(module, response, workflow_nodes, workflow_id):
|
|||||||
if workflow_node['unified_job_template']['type'] != 'workflow_approval':
|
if workflow_node['unified_job_template']['type'] != 'workflow_approval':
|
||||||
module.fail_json(msg="Unable to Find unified_job_template: {0}".format(search_fields))
|
module.fail_json(msg="Unable to Find unified_job_template: {0}".format(search_fields))
|
||||||
|
|
||||||
inventory = workflow_node.get('inventory')
|
|
||||||
if inventory:
|
|
||||||
workflow_node_fields['inventory'] = module.resolve_name_to_id('inventories', inventory)
|
|
||||||
|
|
||||||
# Lookup Values for other fields
|
# Lookup Values for other fields
|
||||||
|
|
||||||
for field_name in (
|
for field_name in (
|
||||||
@@ -645,6 +659,17 @@ def create_workflow_nodes(module, response, workflow_nodes, workflow_id):
|
|||||||
'execution_environments', name_or_id=workflow_node['execution_environment']['name']
|
'execution_environments', name_or_id=workflow_node['execution_environment']['name']
|
||||||
)['id']
|
)['id']
|
||||||
|
|
||||||
|
# Two lookup methods are used based on a fix added in 21.11.0, and the awx export model
|
||||||
|
if 'inventory' in workflow_node:
|
||||||
|
if 'name' in workflow_node['inventory']:
|
||||||
|
inv_lookup_data = {}
|
||||||
|
if 'organization' in workflow_node['inventory']:
|
||||||
|
inv_lookup_data['organization'] = module.resolve_name_to_id('organizations', workflow_node['inventory']['organization']['name'])
|
||||||
|
workflow_node_fields['inventory'] = module.get_one(
|
||||||
|
'inventories', name_or_id=workflow_node['inventory']['name'], data=inv_lookup_data)['id']
|
||||||
|
else:
|
||||||
|
workflow_node_fields['inventory'] = module.get_one('inventories', name_or_id=workflow_node['inventory'])['id']
|
||||||
|
|
||||||
# Set Search fields
|
# Set Search fields
|
||||||
search_fields['workflow_job_template'] = workflow_node_fields['workflow_job_template'] = workflow_id
|
search_fields['workflow_job_template'] = workflow_node_fields['workflow_job_template'] = workflow_id
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import glob
|
|||||||
# Normally a read-only endpoint should not have a module (i.e. /api/v2/me) but sometimes we reuse a name
|
# Normally a read-only endpoint should not have a module (i.e. /api/v2/me) but sometimes we reuse a name
|
||||||
# For example, we have a role module but /api/v2/roles is a read only endpoint.
|
# For example, we have a role module but /api/v2/roles is a read only endpoint.
|
||||||
# This list indicates which read-only endpoints have associated modules with them.
|
# This list indicates which read-only endpoints have associated modules with them.
|
||||||
read_only_endpoints_with_modules = ['settings', 'role', 'project_update']
|
read_only_endpoints_with_modules = ['settings', 'role', 'project_update', 'workflow_approval']
|
||||||
|
|
||||||
# If a module should not be created for an endpoint and the endpoint is not read-only add it here
|
# If a module should not be created for an endpoint and the endpoint is not read-only add it here
|
||||||
# THINK HARD ABOUT DOING THIS
|
# THINK HARD ABOUT DOING THIS
|
||||||
|
|||||||
@@ -95,6 +95,22 @@
|
|||||||
- results is failed
|
- results is failed
|
||||||
- "'In rule 2 end_on must either be an integer or in the format YYYY-MM-DD [HH:MM:SS]' in results.msg"
|
- "'In rule 2 end_on must either be an integer or in the format YYYY-MM-DD [HH:MM:SS]' in results.msg"
|
||||||
|
|
||||||
|
- name: Every Mondays
|
||||||
|
set_fact:
|
||||||
|
complex_rule: "{{ query(ruleset_plugin_name, '2022-04-30 10:30:45', rules=rrules, timezone='UTC' ) }}"
|
||||||
|
ignore_errors: True
|
||||||
|
register: results
|
||||||
|
vars:
|
||||||
|
rrules:
|
||||||
|
- frequency: 'day'
|
||||||
|
interval: 1
|
||||||
|
byweekday: 'monday'
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- results is success
|
||||||
|
- "'DTSTART;TZID=UTC:20220430T103045 RRULE:FREQ=DAILY;BYDAY=MO;INTERVAL=1' == complex_rule"
|
||||||
|
|
||||||
|
|
||||||
- name: call rruleset with an invalid byweekday
|
- name: call rruleset with an invalid byweekday
|
||||||
set_fact:
|
set_fact:
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
---
|
||||||
|
- name: Generate a random string for names
|
||||||
|
set_fact:
|
||||||
|
test_id: "{{ lookup('password', '/dev/null chars=ascii_letters length=16') }}"
|
||||||
|
test_prefix: AWX-Collection-tests-workflow_approval
|
||||||
|
|
||||||
|
- name: Generate random names for test objects
|
||||||
|
set_fact:
|
||||||
|
org_name: "{{ test_prefix }}-org-{{ test_id }}"
|
||||||
|
approval_node_name: "{{ test_prefix }}-node-{{ test_id }}"
|
||||||
|
wfjt_name: "{{ test_prefix }}-wfjt-{{ test_id }}"
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Create a new organization for test isolation
|
||||||
|
organization:
|
||||||
|
name: "{{ org_name }}"
|
||||||
|
|
||||||
|
- name: Create a workflow job template
|
||||||
|
workflow_job_template:
|
||||||
|
name: "{{ wfjt_name }}"
|
||||||
|
organization: "{{ org_name }}"
|
||||||
|
|
||||||
|
- name: Create approval node
|
||||||
|
workflow_job_template_node:
|
||||||
|
identifier: approval_test
|
||||||
|
approval_node:
|
||||||
|
name: "{{ approval_node_name }}" # Referenced later on
|
||||||
|
timeout: 900
|
||||||
|
workflow: "{{ wfjt_name }}"
|
||||||
|
|
||||||
|
# Launch and approve the workflow
|
||||||
|
- name: Launch the workflow
|
||||||
|
workflow_launch:
|
||||||
|
workflow_template: "{{ wfjt_name }}"
|
||||||
|
wait: False
|
||||||
|
register: workflow_job
|
||||||
|
|
||||||
|
- name: Wait for approval node to activate and approve
|
||||||
|
workflow_approval:
|
||||||
|
workflow_job_id: "{{ workflow_job.id }}"
|
||||||
|
name: "{{ approval_node_name }}"
|
||||||
|
interval: 10
|
||||||
|
timeout: 20
|
||||||
|
action: approve
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "result is changed"
|
||||||
|
- "result is not failed"
|
||||||
|
|
||||||
|
always:
|
||||||
|
- name: Delete the workflow job template
|
||||||
|
workflow_job_template:
|
||||||
|
name: "{{ wfjt_name }}"
|
||||||
|
state: absent
|
||||||
|
ignore_errors: True
|
||||||
@@ -493,6 +493,7 @@
|
|||||||
workflow_job_template:
|
workflow_job_template:
|
||||||
name: "copy_{{ wfjt_name }}"
|
name: "copy_{{ wfjt_name }}"
|
||||||
organization: Default
|
organization: Default
|
||||||
|
ask_inventory_on_launch: true
|
||||||
survey_spec:
|
survey_spec:
|
||||||
name: Basic Survey
|
name: Basic Survey
|
||||||
description: Basic Survey
|
description: Basic Survey
|
||||||
@@ -737,6 +738,10 @@
|
|||||||
timeout: 23
|
timeout: 23
|
||||||
execution_environment:
|
execution_environment:
|
||||||
name: "{{ ee1 }}"
|
name: "{{ ee1 }}"
|
||||||
|
inventory:
|
||||||
|
name: Test inventory
|
||||||
|
organization:
|
||||||
|
name: Default
|
||||||
related:
|
related:
|
||||||
credentials:
|
credentials:
|
||||||
- name: "{{ scm_cred_name }}"
|
- name: "{{ scm_cred_name }}"
|
||||||
|
|||||||
@@ -75,7 +75,8 @@ In the root of awx-operator:
|
|||||||
-e image_version=devel \
|
-e image_version=devel \
|
||||||
-e image_pull_policy=Always \
|
-e image_pull_policy=Always \
|
||||||
-e service_type=nodeport \
|
-e service_type=nodeport \
|
||||||
-e namespace=awx
|
-e namespace=awx \
|
||||||
|
-e nodeport_port=30080
|
||||||
```
|
```
|
||||||
Check the operator with the following commands:
|
Check the operator with the following commands:
|
||||||
|
|
||||||
|
|||||||
@@ -199,11 +199,11 @@ ADD tools/ansible/roles/dockerfile/files/rsyslog.conf /var/lib/awx/rsyslog/rsysl
|
|||||||
ADD tools/ansible/roles/dockerfile/files/wait-for-migrations /usr/local/bin/wait-for-migrations
|
ADD tools/ansible/roles/dockerfile/files/wait-for-migrations /usr/local/bin/wait-for-migrations
|
||||||
ADD tools/ansible/roles/dockerfile/files/stop-supervisor /usr/local/bin/stop-supervisor
|
ADD tools/ansible/roles/dockerfile/files/stop-supervisor /usr/local/bin/stop-supervisor
|
||||||
|
|
||||||
|
ADD tools/ansible/roles/dockerfile/files/uwsgi.ini /etc/tower/uwsgi.ini
|
||||||
|
|
||||||
## File mappings
|
## File mappings
|
||||||
{% if build_dev|bool %}
|
{% if build_dev|bool %}
|
||||||
ADD tools/docker-compose/launch_awx.sh /usr/bin/launch_awx.sh
|
ADD tools/docker-compose/launch_awx.sh /usr/bin/launch_awx.sh
|
||||||
ADD tools/docker-compose/nginx.conf /etc/nginx/nginx.conf
|
|
||||||
ADD tools/docker-compose/nginx.vh.default.conf /etc/nginx/conf.d/nginx.vh.default.conf
|
|
||||||
ADD tools/docker-compose/start_tests.sh /start_tests.sh
|
ADD tools/docker-compose/start_tests.sh /start_tests.sh
|
||||||
ADD tools/docker-compose/bootstrap_development.sh /usr/bin/bootstrap_development.sh
|
ADD tools/docker-compose/bootstrap_development.sh /usr/bin/bootstrap_development.sh
|
||||||
ADD tools/docker-compose/entrypoint.sh /entrypoint.sh
|
ADD tools/docker-compose/entrypoint.sh /entrypoint.sh
|
||||||
@@ -213,7 +213,6 @@ ADD https://raw.githubusercontent.com/containers/libpod/master/contrib/podmanima
|
|||||||
{% else %}
|
{% else %}
|
||||||
ADD tools/ansible/roles/dockerfile/files/launch_awx.sh /usr/bin/launch_awx.sh
|
ADD tools/ansible/roles/dockerfile/files/launch_awx.sh /usr/bin/launch_awx.sh
|
||||||
ADD tools/ansible/roles/dockerfile/files/launch_awx_task.sh /usr/bin/launch_awx_task.sh
|
ADD tools/ansible/roles/dockerfile/files/launch_awx_task.sh /usr/bin/launch_awx_task.sh
|
||||||
ADD tools/ansible/roles/dockerfile/files/uwsgi.ini /etc/tower/uwsgi.ini
|
|
||||||
ADD {{ template_dest }}/supervisor.conf /etc/supervisord.conf
|
ADD {{ template_dest }}/supervisor.conf /etc/supervisord.conf
|
||||||
ADD {{ template_dest }}/supervisor_task.conf /etc/supervisord_task.conf
|
ADD {{ template_dest }}/supervisor_task.conf /etc/supervisord_task.conf
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ environment =
|
|||||||
DEV_RELOAD_COMMAND='supervisorctl -c /etc/supervisord_task.conf restart all; supervisorctl restart tower-processes:daphne tower-processes:wsbroadcast'
|
DEV_RELOAD_COMMAND='supervisorctl -c /etc/supervisord_task.conf restart all; supervisorctl restart tower-processes:daphne tower-processes:wsbroadcast'
|
||||||
{% else %}
|
{% else %}
|
||||||
command = /var/lib/awx/venv/awx/bin/uwsgi /etc/tower/uwsgi.ini
|
command = /var/lib/awx/venv/awx/bin/uwsgi /etc/tower/uwsgi.ini
|
||||||
directory = /var/lib/awx
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
directory = /var/lib/awx
|
||||||
autorestart = true
|
autorestart = true
|
||||||
startsecs = 30
|
startsecs = 30
|
||||||
stopasgroup=true
|
stopasgroup=true
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ control_plane_node_count: 1
|
|||||||
minikube_container_group: false
|
minikube_container_group: false
|
||||||
receptor_socket_file: /var/run/awx-receptor/receptor.sock
|
receptor_socket_file: /var/run/awx-receptor/receptor.sock
|
||||||
receptor_image: quay.io/ansible/receptor:devel
|
receptor_image: quay.io/ansible/receptor:devel
|
||||||
|
ingress_path: /
|
||||||
|
|
||||||
# Keys for signing work
|
# Keys for signing work
|
||||||
receptor_rsa_bits: 4096
|
receptor_rsa_bits: 4096
|
||||||
|
|||||||
@@ -49,18 +49,11 @@
|
|||||||
mode: '0600'
|
mode: '0600'
|
||||||
with_items:
|
with_items:
|
||||||
- "database.py"
|
- "database.py"
|
||||||
|
- "local_settings.py"
|
||||||
- "websocket_secret.py"
|
- "websocket_secret.py"
|
||||||
- "haproxy.cfg"
|
- "haproxy.cfg"
|
||||||
|
- "nginx.conf"
|
||||||
- name: Delete old local_settings.py
|
- "nginx.locations.conf"
|
||||||
file:
|
|
||||||
path: "{{ playbook_dir }}/../../../awx/settings/local_settings.py"
|
|
||||||
state: absent
|
|
||||||
|
|
||||||
- name: Copy local_settings.py
|
|
||||||
copy:
|
|
||||||
src: "local_settings.py"
|
|
||||||
dest: "{{ sources_dest }}/local_settings.py"
|
|
||||||
|
|
||||||
- name: Get OS info for sdb
|
- name: Get OS info for sdb
|
||||||
shell: |
|
shell: |
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ services:
|
|||||||
EXECUTION_NODE_COUNT: {{ execution_node_count|int }}
|
EXECUTION_NODE_COUNT: {{ execution_node_count|int }}
|
||||||
AWX_LOGGING_MODE: stdout
|
AWX_LOGGING_MODE: stdout
|
||||||
DJANGO_SUPERUSER_PASSWORD: {{ admin_password }}
|
DJANGO_SUPERUSER_PASSWORD: {{ admin_password }}
|
||||||
|
UWSGI_MOUNT_PATH: {{ ingress_path }}
|
||||||
{% if loop.index == 1 %}
|
{% if loop.index == 1 %}
|
||||||
RUN_MIGRATIONS: 1
|
RUN_MIGRATIONS: 1
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -40,6 +41,8 @@ services:
|
|||||||
- "../../docker-compose/_sources/database.py:/etc/tower/conf.d/database.py"
|
- "../../docker-compose/_sources/database.py:/etc/tower/conf.d/database.py"
|
||||||
- "../../docker-compose/_sources/websocket_secret.py:/etc/tower/conf.d/websocket_secret.py"
|
- "../../docker-compose/_sources/websocket_secret.py:/etc/tower/conf.d/websocket_secret.py"
|
||||||
- "../../docker-compose/_sources/local_settings.py:/etc/tower/conf.d/local_settings.py"
|
- "../../docker-compose/_sources/local_settings.py:/etc/tower/conf.d/local_settings.py"
|
||||||
|
- "../../docker-compose/_sources/nginx.conf:/etc/nginx/nginx.conf"
|
||||||
|
- "../../docker-compose/_sources/nginx.locations.conf:/etc/nginx/conf.d/nginx.locations.conf"
|
||||||
- "../../docker-compose/_sources/SECRET_KEY:/etc/tower/SECRET_KEY"
|
- "../../docker-compose/_sources/SECRET_KEY:/etc/tower/SECRET_KEY"
|
||||||
- "../../docker-compose/_sources/receptor/receptor-awx-{{ loop.index }}.conf:/etc/receptor/receptor.conf"
|
- "../../docker-compose/_sources/receptor/receptor-awx-{{ loop.index }}.conf:/etc/receptor/receptor.conf"
|
||||||
- "../../docker-compose/_sources/receptor/receptor-awx-{{ loop.index }}.conf.lock:/etc/receptor/receptor.conf.lock"
|
- "../../docker-compose/_sources/receptor/receptor-awx-{{ loop.index }}.conf.lock:/etc/receptor/receptor.conf.lock"
|
||||||
|
|||||||
@@ -46,3 +46,5 @@ SYSTEM_UUID = '00000000-0000-0000-0000-000000000000'
|
|||||||
BROADCAST_WEBSOCKET_PORT = 8013
|
BROADCAST_WEBSOCKET_PORT = 8013
|
||||||
BROADCAST_WEBSOCKET_VERIFY_CERT = False
|
BROADCAST_WEBSOCKET_VERIFY_CERT = False
|
||||||
BROADCAST_WEBSOCKET_PROTOCOL = 'http'
|
BROADCAST_WEBSOCKET_PROTOCOL = 'http'
|
||||||
|
|
||||||
|
STATIC_URL = '{{ (ingress_path + '/static/').replace('//', '/') }}'
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
#user awx;
|
|
||||||
|
|
||||||
worker_processes 1;
|
worker_processes 1;
|
||||||
|
|
||||||
pid /tmp/nginx.pid;
|
error_log /var/log/nginx/error.log warn;
|
||||||
|
pid /var/run/nginx.pid;
|
||||||
|
|
||||||
events {
|
events {
|
||||||
worker_connections 1024;
|
worker_connections 1024;
|
||||||
@@ -17,7 +16,7 @@ http {
|
|||||||
'$status $body_bytes_sent "$http_referer" '
|
'$status $body_bytes_sent "$http_referer" '
|
||||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||||
|
|
||||||
access_log /dev/stdout main;
|
access_log /var/log/nginx/access.log main;
|
||||||
|
|
||||||
map $http_upgrade $connection_upgrade {
|
map $http_upgrade $connection_upgrade {
|
||||||
default upgrade;
|
default upgrade;
|
||||||
@@ -25,41 +24,17 @@ http {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sendfile on;
|
sendfile on;
|
||||||
#tcp_nopush on;
|
|
||||||
#gzip on;
|
|
||||||
|
|
||||||
upstream uwsgi {
|
upstream uwsgi {
|
||||||
server 127.0.0.1:8050;
|
server localhost:8050;
|
||||||
}
|
}
|
||||||
|
|
||||||
upstream daphne {
|
upstream daphne {
|
||||||
server 127.0.0.1:8051;
|
server localhost:8051;
|
||||||
}
|
}
|
||||||
|
|
||||||
{% if ssl_certificate is defined %}
|
|
||||||
server {
|
server {
|
||||||
listen 8052 default_server;
|
listen 8013 default_server;
|
||||||
server_name _;
|
|
||||||
|
|
||||||
# Redirect all HTTP links to the matching HTTPS page
|
|
||||||
return 301 https://$host$request_uri;
|
|
||||||
}
|
|
||||||
{%endif %}
|
|
||||||
|
|
||||||
server {
|
|
||||||
{% if (ssl_certificate is defined) and (ssl_certificate_key is defined) %}
|
|
||||||
listen 8053 ssl;
|
|
||||||
|
|
||||||
ssl_certificate /etc/nginx/awxweb.pem;
|
|
||||||
ssl_certificate_key /etc/nginx/awxweb_key.pem;
|
|
||||||
{% elif (ssl_certificate is defined) and (ssl_certificate_key is not defined) %}
|
|
||||||
listen 8053 ssl;
|
|
||||||
|
|
||||||
ssl_certificate /etc/nginx/awxweb.pem;
|
|
||||||
ssl_certificate_key /etc/nginx/awxweb.pem;
|
|
||||||
{% else %}
|
|
||||||
listen 8052 default_server;
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
# If you have a domain name, this is where to add it
|
# If you have a domain name, this is where to add it
|
||||||
server_name _;
|
server_name _;
|
||||||
@@ -67,56 +42,35 @@ http {
|
|||||||
|
|
||||||
# HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
|
# HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
|
||||||
add_header Strict-Transport-Security max-age=15768000;
|
add_header Strict-Transport-Security max-age=15768000;
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
|
||||||
# Protect against click-jacking https://www.owasp.org/index.php/Testing_for_Clickjacking_(OTG-CLIENT-009)
|
include /etc/nginx/conf.d/*.conf;
|
||||||
add_header X-Frame-Options "DENY";
|
}
|
||||||
|
|
||||||
location /nginx_status {
|
server {
|
||||||
stub_status on;
|
listen 8043 default_server ssl;
|
||||||
access_log off;
|
|
||||||
allow 127.0.0.1;
|
|
||||||
deny all;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /static/ {
|
# If you have a domain name, this is where to add it
|
||||||
alias /var/lib/awx/public/static/;
|
server_name _;
|
||||||
}
|
keepalive_timeout 65;
|
||||||
|
|
||||||
location /favicon.ico { alias /var/lib/awx/public/static/favicon.ico; }
|
ssl_certificate /etc/nginx/nginx.crt;
|
||||||
|
ssl_certificate_key /etc/nginx/nginx.key;
|
||||||
|
|
||||||
location /websocket {
|
ssl_session_timeout 1d;
|
||||||
# Pass request to the upstream alias
|
ssl_session_cache shared:SSL:50m;
|
||||||
proxy_pass http://daphne;
|
ssl_session_tickets off;
|
||||||
# Require http version 1.1 to allow for upgrade requests
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
# We want proxy_buffering off for proxying to websockets.
|
|
||||||
proxy_buffering off;
|
|
||||||
# http://en.wikipedia.org/wiki/X-Forwarded-For
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
# enable this if you use HTTPS:
|
|
||||||
proxy_set_header X-Forwarded-Proto https;
|
|
||||||
# pass the Host: header from the client for the sake of redirects
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
# We've set the Host header, so we don't need Nginx to muddle
|
|
||||||
# about with redirects
|
|
||||||
proxy_redirect off;
|
|
||||||
# Depending on the request value, set the Upgrade and
|
|
||||||
# connection headers
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection $connection_upgrade;
|
|
||||||
}
|
|
||||||
|
|
||||||
location / {
|
# intermediate configuration. tweak to your needs.
|
||||||
# Add trailing / if missing
|
ssl_protocols TLSv1.2;
|
||||||
rewrite ^(.*)$http_host(.*[^/])$ $1$http_host$2/ permanent;
|
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
|
||||||
uwsgi_read_timeout 120s;
|
ssl_prefer_server_ciphers on;
|
||||||
uwsgi_pass uwsgi;
|
|
||||||
include /etc/nginx/uwsgi_params;
|
# HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
|
||||||
{%- if extra_nginx_include is defined %}
|
add_header Strict-Transport-Security max-age=15768000;
|
||||||
include {{ extra_nginx_include }};
|
add_header X-Content-Type-Options nosniff;
|
||||||
{%- endif %}
|
|
||||||
proxy_set_header X-Forwarded-Port 443;
|
|
||||||
uwsgi_param HTTP_X_FORWARDED_PORT 443;
|
include /etc/nginx/conf.d/*.conf;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
location {{ (ingress_path + '/static').replace('//', '/') }} {
|
||||||
|
alias /var/lib/awx/public/static/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location {{ (ingress_path + '/favicon.ico').replace('//', '/') }} {
|
||||||
|
alias /awx_devel/awx/public/static/favicon.ico;
|
||||||
|
}
|
||||||
|
|
||||||
|
location {{ (ingress_path + '/websocket').replace('//', '/') }} {
|
||||||
|
# Pass request to the upstream alias
|
||||||
|
proxy_pass http://daphne;
|
||||||
|
# Require http version 1.1 to allow for upgrade requests
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
# We want proxy_buffering off for proxying to websockets.
|
||||||
|
proxy_buffering off;
|
||||||
|
# http://en.wikipedia.org/wiki/X-Forwarded-For
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
# enable this if you use HTTPS:
|
||||||
|
proxy_set_header X-Forwarded-Proto https;
|
||||||
|
# pass the Host: header from the client for the sake of redirects
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
# We've set the Host header, so we don't need Nginx to muddle
|
||||||
|
# about with redirects
|
||||||
|
proxy_redirect off;
|
||||||
|
# Depending on the request value, set the Upgrade and
|
||||||
|
# connection headers
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection $connection_upgrade;
|
||||||
|
}
|
||||||
|
|
||||||
|
location {{ ingress_path }} {
|
||||||
|
# Add trailing / if missing
|
||||||
|
rewrite ^(.*[^/])$ $1/ permanent;
|
||||||
|
uwsgi_read_timeout 120s;
|
||||||
|
uwsgi_pass uwsgi;
|
||||||
|
include /etc/nginx/uwsgi_params;
|
||||||
|
}
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
worker_processes 1;
|
|
||||||
|
|
||||||
error_log /var/log/nginx/error.log warn;
|
|
||||||
pid /var/run/nginx.pid;
|
|
||||||
|
|
||||||
events {
|
|
||||||
worker_connections 1024;
|
|
||||||
}
|
|
||||||
|
|
||||||
http {
|
|
||||||
include /etc/nginx/mime.types;
|
|
||||||
default_type application/octet-stream;
|
|
||||||
server_tokens off;
|
|
||||||
|
|
||||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
|
||||||
'$status $body_bytes_sent "$http_referer" '
|
|
||||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
|
||||||
|
|
||||||
access_log /var/log/nginx/access.log main;
|
|
||||||
|
|
||||||
map $http_upgrade $connection_upgrade {
|
|
||||||
default upgrade;
|
|
||||||
'' close;
|
|
||||||
}
|
|
||||||
|
|
||||||
sendfile on;
|
|
||||||
#tcp_nopush on;
|
|
||||||
#gzip on;
|
|
||||||
|
|
||||||
include /etc/nginx/conf.d/*.conf;
|
|
||||||
}
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
upstream uwsgi {
|
|
||||||
server localhost:8050;
|
|
||||||
}
|
|
||||||
|
|
||||||
upstream daphne {
|
|
||||||
server localhost:8051;
|
|
||||||
}
|
|
||||||
|
|
||||||
# server {
|
|
||||||
# listen 8013 default_server;
|
|
||||||
# listen [::]:8013 default_server;
|
|
||||||
# server_name _;
|
|
||||||
# return 301 https://$host:8043$request_uri;
|
|
||||||
# }
|
|
||||||
|
|
||||||
server {
|
|
||||||
listen 8013 default_server;
|
|
||||||
|
|
||||||
# If you have a domain name, this is where to add it
|
|
||||||
server_name _;
|
|
||||||
keepalive_timeout 65;
|
|
||||||
|
|
||||||
# HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
|
|
||||||
add_header Strict-Transport-Security max-age=15768000;
|
|
||||||
add_header X-Content-Type-Options nosniff;
|
|
||||||
|
|
||||||
location /static/ {
|
|
||||||
alias /var/lib/awx/public/static/;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /favicon.ico { alias /awx_devel/awx/public/static/favicon.ico; }
|
|
||||||
|
|
||||||
location ~ ^/websocket {
|
|
||||||
# Pass request to the upstream alias
|
|
||||||
proxy_pass http://daphne;
|
|
||||||
# Require http version 1.1 to allow for upgrade requests
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
# We want proxy_buffering off for proxying to websockets.
|
|
||||||
proxy_buffering off;
|
|
||||||
# http://en.wikipedia.org/wiki/X-Forwarded-For
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
# enable this if you use HTTPS:
|
|
||||||
proxy_set_header X-Forwarded-Proto https;
|
|
||||||
# pass the Host: header from the client for the sake of redirects
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
# We've set the Host header, so we don't need Nginx to muddle
|
|
||||||
# about with redirects
|
|
||||||
proxy_redirect off;
|
|
||||||
# Depending on the request value, set the Upgrade and
|
|
||||||
# connection headers
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection $connection_upgrade;
|
|
||||||
}
|
|
||||||
|
|
||||||
location / {
|
|
||||||
# Add trailing / if missing
|
|
||||||
rewrite ^(.*[^/])$ $1/ permanent;
|
|
||||||
uwsgi_read_timeout 120s;
|
|
||||||
uwsgi_pass uwsgi;
|
|
||||||
include /etc/nginx/uwsgi_params;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
server {
|
|
||||||
listen 8043 default_server ssl;
|
|
||||||
|
|
||||||
# If you have a domain name, this is where to add it
|
|
||||||
server_name _;
|
|
||||||
keepalive_timeout 65;
|
|
||||||
|
|
||||||
ssl_certificate /etc/nginx/nginx.crt;
|
|
||||||
ssl_certificate_key /etc/nginx/nginx.key;
|
|
||||||
|
|
||||||
ssl_session_timeout 1d;
|
|
||||||
ssl_session_cache shared:SSL:50m;
|
|
||||||
ssl_session_tickets off;
|
|
||||||
|
|
||||||
# intermediate configuration. tweak to your needs.
|
|
||||||
ssl_protocols TLSv1.2;
|
|
||||||
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
|
|
||||||
ssl_prefer_server_ciphers on;
|
|
||||||
|
|
||||||
# HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
|
|
||||||
add_header Strict-Transport-Security max-age=15768000;
|
|
||||||
add_header X-Content-Type-Options nosniff;
|
|
||||||
|
|
||||||
location /static/ {
|
|
||||||
alias /var/lib/awx/public/static/;
|
|
||||||
access_log off;
|
|
||||||
sendfile off;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /favicon.ico { alias /awx_devel/awx/public/static/favicon.ico; }
|
|
||||||
|
|
||||||
location ~ ^/websocket {
|
|
||||||
# Pass request to the upstream alias
|
|
||||||
proxy_pass http://daphne;
|
|
||||||
# Require http version 1.1 to allow for upgrade requests
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
# We want proxy_buffering off for proxying to websockets.
|
|
||||||
proxy_buffering off;
|
|
||||||
# http://en.wikipedia.org/wiki/X-Forwarded-For
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
# enable this if you use HTTPS:
|
|
||||||
proxy_set_header X-Forwarded-Proto https;
|
|
||||||
# pass the Host: header from the client for the sake of redirects
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
# We've set the Host header, so we don't need Nginx to muddle
|
|
||||||
# about with redirects
|
|
||||||
proxy_redirect off;
|
|
||||||
# Depending on the request value, set the Upgrade and
|
|
||||||
# connection headers
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection $connection_upgrade;
|
|
||||||
}
|
|
||||||
|
|
||||||
location / {
|
|
||||||
# Add trailing / if missing
|
|
||||||
rewrite ^(.*[^/])$ $1/ permanent;
|
|
||||||
uwsgi_read_timeout 120s;
|
|
||||||
uwsgi_pass uwsgi;
|
|
||||||
include /etc/nginx/uwsgi_params;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user