mirror of
https://github.com/ansible/awx.git
synced 2026-03-21 19:07:39 -02:30
Merge branch 'purge_ansible_name' into release_3.2.0
* purge_ansible_name: Remove ansible reference from dev PKG-INFO Add back in PRIVILEGE_ESCALATION_METHODS inadvertantly removed Add awx_ and AWX_ environment vars and extra_vars alongside Tower Refactor some tower periodic tasks to label as awx Refactor Notification backend for tower -> awx Refactor fact cache plugin from tower -> awx Rename tower display plugins to awx display Mass rename from ansible_(awx|tower) -> (awx|tower)
This commit is contained in:
@@ -7,7 +7,7 @@ import warnings
|
|||||||
|
|
||||||
from pkg_resources import get_distribution
|
from pkg_resources import get_distribution
|
||||||
|
|
||||||
__version__ = get_distribution('ansible-awx').version
|
__version__ = get_distribution('awx').version
|
||||||
|
|
||||||
__all__ = ['__version__']
|
__all__ = ['__version__']
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ from django.utils.translation import ugettext_lazy as _
|
|||||||
from rest_framework.exceptions import ParseError, PermissionDenied
|
from rest_framework.exceptions import ParseError, PermissionDenied
|
||||||
from rest_framework.filters import BaseFilterBackend
|
from rest_framework.filters import BaseFilterBackend
|
||||||
|
|
||||||
# Ansible Tower
|
# AWX
|
||||||
from awx.main.utils import get_type_for_model, to_python_boolean
|
from awx.main.utils import get_type_for_model, to_python_boolean
|
||||||
from awx.main.models.credential import CredentialType
|
from awx.main.models.credential import CredentialType
|
||||||
from awx.main.models.rbac import RoleAncestorEntry
|
from awx.main.models.rbac import RoleAncestorEntry
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ from rest_framework import serializers
|
|||||||
from rest_framework.relations import RelatedField, ManyRelatedField
|
from rest_framework.relations import RelatedField, ManyRelatedField
|
||||||
from rest_framework.request import clone_request
|
from rest_framework.request import clone_request
|
||||||
|
|
||||||
# Ansible Tower
|
# AWX
|
||||||
from awx.main.models import InventorySource, NotificationTemplate
|
from awx.main.models import InventorySource, NotificationTemplate
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
The root of the Ansible Tower REST API.
|
The root of the REST API.
|
||||||
|
|
||||||
Make a GET request to this resource to obtain information about the available
|
Make a GET request to this resource to obtain information about the available
|
||||||
API versions.
|
API versions.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Version 2 of the Ansible Tower REST API.
|
Version 2 of the REST API.
|
||||||
|
|
||||||
Make a GET request to this resource to obtain a list of all child resources
|
Make a GET request to this resource to obtain a list of all child resources
|
||||||
available via the API.
|
available via the API.
|
||||||
|
|||||||
@@ -17,9 +17,9 @@
|
|||||||
|
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
|
|
||||||
# Tower Display Callback
|
# AWX Display Callback
|
||||||
from . import cleanup # noqa (registers control persistent cleanup)
|
from . import cleanup # noqa (registers control persistent cleanup)
|
||||||
from . import display # noqa (wraps ansible.display.Display methods)
|
from . import display # noqa (wraps ansible.display.Display methods)
|
||||||
from .module import TowerDefaultCallbackModule, TowerMinimalCallbackModule
|
from .module import AWXDefaultCallbackModule, AWXMinimalCallbackModule
|
||||||
|
|
||||||
__all__ = ['TowerDefaultCallbackModule', 'TowerMinimalCallbackModule']
|
__all__ = ['AWXDefaultCallbackModule', 'AWXMinimalCallbackModule']
|
||||||
@@ -27,7 +27,7 @@ from copy import copy
|
|||||||
from ansible.plugins.callback import CallbackBase
|
from ansible.plugins.callback import CallbackBase
|
||||||
from ansible.plugins.callback.default import CallbackModule as DefaultCallbackModule
|
from ansible.plugins.callback.default import CallbackModule as DefaultCallbackModule
|
||||||
|
|
||||||
# Tower Display Callback
|
# AWX Display Callback
|
||||||
from .events import event_context
|
from .events import event_context
|
||||||
from .minimal import CallbackModule as MinimalCallbackModule
|
from .minimal import CallbackModule as MinimalCallbackModule
|
||||||
|
|
||||||
@@ -448,12 +448,12 @@ class BaseCallbackModule(CallbackBase):
|
|||||||
super(BaseCallbackModule, self).v2_runner_retry(result)
|
super(BaseCallbackModule, self).v2_runner_retry(result)
|
||||||
|
|
||||||
|
|
||||||
class TowerDefaultCallbackModule(BaseCallbackModule, DefaultCallbackModule):
|
class AWXDefaultCallbackModule(BaseCallbackModule, DefaultCallbackModule):
|
||||||
|
|
||||||
CALLBACK_NAME = 'tower_display'
|
CALLBACK_NAME = 'awx_display'
|
||||||
|
|
||||||
|
|
||||||
class TowerMinimalCallbackModule(BaseCallbackModule, MinimalCallbackModule):
|
class AWXMinimalCallbackModule(BaseCallbackModule, MinimalCallbackModule):
|
||||||
|
|
||||||
CALLBACK_NAME = 'minimal'
|
CALLBACK_NAME = 'minimal'
|
||||||
|
|
||||||
@@ -27,4 +27,4 @@ if awx_lib_path not in sys.path:
|
|||||||
sys.path.insert(0, awx_lib_path)
|
sys.path.insert(0, awx_lib_path)
|
||||||
|
|
||||||
# Tower Display Callback
|
# Tower Display Callback
|
||||||
from tower_display_callback import TowerDefaultCallbackModule as CallbackModule # noqa
|
from awx_display_callback import AWXDefaultCallbackModule as CallbackModule # noqa
|
||||||
@@ -27,4 +27,4 @@ if awx_lib_path not in sys.path:
|
|||||||
sys.path.insert(0, awx_lib_path)
|
sys.path.insert(0, awx_lib_path)
|
||||||
|
|
||||||
# Tower Display Callback
|
# Tower Display Callback
|
||||||
from tower_display_callback import TowerMinimalCallbackModule as CallbackModule # noqa
|
from awx_display_callback import AWXMinimalCallbackModule as CallbackModule # noqa
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
# Based on http://stackoverflow.com/a/6879344/131141 -- Initialize tower display
|
# Based on http://stackoverflow.com/a/6879344/131141 -- Initialize awx display
|
||||||
# callback as early as possible to wrap ansible.display.Display methods.
|
# callback as early as possible to wrap ansible.display.Display methods.
|
||||||
|
|
||||||
|
|
||||||
def argv_ready(argv):
|
def argv_ready(argv):
|
||||||
if argv and os.path.basename(argv[0]) in {'ansible', 'ansible-playbook'}:
|
if argv and os.path.basename(argv[0]) in {'ansible', 'ansible-playbook'}:
|
||||||
import tower_display_callback # noqa
|
import awx_display_callback # noqa
|
||||||
|
|
||||||
|
|
||||||
class argv_placeholder(object):
|
class argv_placeholder(object):
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ import pytest
|
|||||||
# search for a plugin implementation (which should be named `CallbackModule`)
|
# search for a plugin implementation (which should be named `CallbackModule`)
|
||||||
#
|
#
|
||||||
# this code modifies the Python path to make our
|
# this code modifies the Python path to make our
|
||||||
# `awx.lib.tower_display_callback` callback importable (because `awx.lib`
|
# `awx.lib.awx_display_callback` callback importable (because `awx.lib`
|
||||||
# itself is not a package)
|
# itself is not a package)
|
||||||
#
|
#
|
||||||
# we use the `tower_display_callback` imports below within this file, but
|
# we use the `awx_display_callback` imports below within this file, but
|
||||||
# Ansible also uses them when it discovers this file in
|
# Ansible also uses them when it discovers this file in
|
||||||
# `ANSIBLE_CALLBACK_PLUGINS`
|
# `ANSIBLE_CALLBACK_PLUGINS`
|
||||||
CALLBACK = os.path.splitext(os.path.basename(__file__))[0]
|
CALLBACK = os.path.splitext(os.path.basename(__file__))[0]
|
||||||
@@ -32,8 +32,8 @@ with mock.patch.dict(os.environ, {'ANSIBLE_STDOUT_CALLBACK': CALLBACK,
|
|||||||
if path not in sys.path:
|
if path not in sys.path:
|
||||||
sys.path.insert(0, path)
|
sys.path.insert(0, path)
|
||||||
|
|
||||||
from tower_display_callback import TowerDefaultCallbackModule as CallbackModule # noqa
|
from awx_display_callback import AWXDefaultCallbackModule as CallbackModule # noqa
|
||||||
from tower_display_callback.events import event_context # noqa
|
from awx_display_callback.events import event_context # noqa
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ class IsolatedManager(object):
|
|||||||
isolated_ssh_path = None
|
isolated_ssh_path = None
|
||||||
try:
|
try:
|
||||||
if getattr(settings, 'AWX_ISOLATED_PRIVATE_KEY', None):
|
if getattr(settings, 'AWX_ISOLATED_PRIVATE_KEY', None):
|
||||||
isolated_ssh_path = tempfile.mkdtemp(prefix='ansible_awx_isolated', dir=settings.AWX_PROOT_BASE_PATH)
|
isolated_ssh_path = tempfile.mkdtemp(prefix='awx_isolated', dir=settings.AWX_PROOT_BASE_PATH)
|
||||||
os.chmod(isolated_ssh_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
|
os.chmod(isolated_ssh_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
|
||||||
isolated_key = os.path.join(isolated_ssh_path, '.isolated')
|
isolated_key = os.path.join(isolated_ssh_path, '.isolated')
|
||||||
ssh_sock = os.path.join(isolated_ssh_path, '.isolated_ssh_auth.sock')
|
ssh_sock = os.path.join(isolated_ssh_path, '.isolated_ssh_auth.sock')
|
||||||
|
|||||||
@@ -180,15 +180,15 @@ def run_isolated_job(private_data_dir, secrets, logfile=sys.stdout):
|
|||||||
pexpect_timeout = secrets.get('pexpect_timeout', 5)
|
pexpect_timeout = secrets.get('pexpect_timeout', 5)
|
||||||
|
|
||||||
# Use local callback directory
|
# Use local callback directory
|
||||||
callback_dir = os.getenv('TOWER_LIB_DIRECTORY')
|
callback_dir = os.getenv('AWX_LIB_DIRECTORY')
|
||||||
if callback_dir is None:
|
if callback_dir is None:
|
||||||
raise RuntimeError('Location for Tower Ansible callbacks must be specified '
|
raise RuntimeError('Location for callbacks must be specified '
|
||||||
'by environment variable TOWER_LIB_DIRECTORY.')
|
'by environment variable AWX_LIB_DIRECTORY.')
|
||||||
env['ANSIBLE_CALLBACK_PLUGINS'] = os.path.join(callback_dir, 'isolated_callbacks')
|
env['ANSIBLE_CALLBACK_PLUGINS'] = os.path.join(callback_dir, 'isolated_callbacks')
|
||||||
if 'AD_HOC_COMMAND_ID' in env:
|
if 'AD_HOC_COMMAND_ID' in env:
|
||||||
env['ANSIBLE_STDOUT_CALLBACK'] = 'minimal'
|
env['ANSIBLE_STDOUT_CALLBACK'] = 'minimal'
|
||||||
else:
|
else:
|
||||||
env['ANSIBLE_STDOUT_CALLBACK'] = 'tower_display'
|
env['ANSIBLE_STDOUT_CALLBACK'] = 'awx_display'
|
||||||
env['AWX_ISOLATED_DATA_DIR'] = private_data_dir
|
env['AWX_ISOLATED_DATA_DIR'] = private_data_dir
|
||||||
env['PYTHONPATH'] = env.get('PYTHONPATH', '') + callback_dir + ':'
|
env['PYTHONPATH'] = env.get('PYTHONPATH', '') + callback_dir + ':'
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ from taggit.managers import TaggableManager
|
|||||||
# Django-CRUM
|
# Django-CRUM
|
||||||
from crum import get_current_user
|
from crum import get_current_user
|
||||||
|
|
||||||
# Ansible Tower
|
# AWX
|
||||||
from awx.main.utils import encrypt_field
|
from awx.main.utils import encrypt_field
|
||||||
|
|
||||||
__all__ = ['prevent_search', 'VarsDictProperty', 'BaseModel', 'CreatedModifiedModel',
|
__all__ = ['prevent_search', 'VarsDictProperty', 'BaseModel', 'CreatedModifiedModel',
|
||||||
|
|||||||
@@ -384,7 +384,7 @@ class CredentialType(CommonModelNameNotUnique):
|
|||||||
'VIRTUAL_ENV', 'PATH', 'PYTHONPATH', 'PROOT_TMP_DIR', 'JOB_ID',
|
'VIRTUAL_ENV', 'PATH', 'PYTHONPATH', 'PROOT_TMP_DIR', 'JOB_ID',
|
||||||
'INVENTORY_ID', 'INVENTORY_SOURCE_ID', 'INVENTORY_UPDATE_ID',
|
'INVENTORY_ID', 'INVENTORY_SOURCE_ID', 'INVENTORY_UPDATE_ID',
|
||||||
'AD_HOC_COMMAND_ID', 'REST_API_URL', 'REST_API_TOKEN', 'TOWER_HOST',
|
'AD_HOC_COMMAND_ID', 'REST_API_URL', 'REST_API_TOKEN', 'TOWER_HOST',
|
||||||
'MAX_EVENT_RES', 'CALLBACK_QUEUE', 'CALLBACK_CONNECTION', 'CACHE',
|
'AWX_HOST', 'MAX_EVENT_RES', 'CALLBACK_QUEUE', 'CALLBACK_CONNECTION', 'CACHE',
|
||||||
'JOB_CALLBACK_DEBUG', 'INVENTORY_HOSTVARS', 'FACT_QUEUE',
|
'JOB_CALLBACK_DEBUG', 'INVENTORY_HOSTVARS', 'FACT_QUEUE',
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ __all__ = ('Instance', 'InstanceGroup', 'JobOrigin', 'TowerScheduleState',)
|
|||||||
|
|
||||||
|
|
||||||
class Instance(models.Model):
|
class Instance(models.Model):
|
||||||
"""A model representing an Ansible Tower instance running against this database."""
|
"""A model representing an AWX instance running against this database."""
|
||||||
objects = InstanceManager()
|
objects = InstanceManager()
|
||||||
|
|
||||||
uuid = models.CharField(max_length=40)
|
uuid = models.CharField(max_length=40)
|
||||||
@@ -51,11 +51,11 @@ class Instance(models.Model):
|
|||||||
@property
|
@property
|
||||||
def role(self):
|
def role(self):
|
||||||
# NOTE: TODO: Likely to repurpose this once standalone ramparts are a thing
|
# NOTE: TODO: Likely to repurpose this once standalone ramparts are a thing
|
||||||
return "tower"
|
return "awx"
|
||||||
|
|
||||||
|
|
||||||
class InstanceGroup(models.Model):
|
class InstanceGroup(models.Model):
|
||||||
"""A model representing a Queue/Group of Tower Instances."""
|
"""A model representing a Queue/Group of AWX Instances."""
|
||||||
name = models.CharField(max_length=250, unique=True)
|
name = models.CharField(max_length=250, unique=True)
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
modified = models.DateTimeField(auto_now=True)
|
modified = models.DateTimeField(auto_now=True)
|
||||||
|
|||||||
@@ -194,11 +194,11 @@ class JobNotificationMixin(object):
|
|||||||
|
|
||||||
def _build_notification_message(self, status_str):
|
def _build_notification_message(self, status_str):
|
||||||
notification_body = self.notification_data()
|
notification_body = self.notification_data()
|
||||||
notification_subject = u"{} #{} '{}' {} on Ansible Tower: {}".format(self.get_notification_friendly_name(),
|
notification_subject = u"{} #{} '{}' {}: {}".format(self.get_notification_friendly_name(),
|
||||||
self.id,
|
self.id,
|
||||||
self.name,
|
self.name,
|
||||||
status_str,
|
status_str,
|
||||||
notification_body['url'])
|
notification_body['url'])
|
||||||
notification_body['friendly_name'] = self.get_notification_friendly_name()
|
notification_body['friendly_name'] = self.get_notification_friendly_name()
|
||||||
return (notification_subject, notification_body)
|
return (notification_subject, notification_body)
|
||||||
|
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ from django.core.mail.backends.base import BaseEmailBackend
|
|||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
class TowerBaseEmailBackend(BaseEmailBackend):
|
class AWXBaseEmailBackend(BaseEmailBackend):
|
||||||
|
|
||||||
def format_body(self, body):
|
def format_body(self, body):
|
||||||
if "body" in body:
|
if "body" in body:
|
||||||
body_actual = body['body']
|
body_actual = body['body']
|
||||||
else:
|
else:
|
||||||
body_actual = smart_text(_("{} #{} had status {} on Ansible Tower, view details at {}\n\n").format(
|
body_actual = smart_text(_("{} #{} had status {}, view details at {}\n\n").format(
|
||||||
body['friendly_name'], body['id'], body['status'], body['url'])
|
body['friendly_name'], body['id'], body['status'], body['url'])
|
||||||
)
|
)
|
||||||
body_actual += json.dumps(body, indent=4)
|
body_actual += json.dumps(body, indent=4)
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ import requests
|
|||||||
|
|
||||||
from django.utils.encoding import smart_text
|
from django.utils.encoding import smart_text
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from awx.main.notifications.base import TowerBaseEmailBackend
|
from awx.main.notifications.base import AWXBaseEmailBackend
|
||||||
|
|
||||||
logger = logging.getLogger('awx.main.notifications.hipchat_backend')
|
logger = logging.getLogger('awx.main.notifications.hipchat_backend')
|
||||||
|
|
||||||
|
|
||||||
class HipChatBackend(TowerBaseEmailBackend):
|
class HipChatBackend(AWXBaseEmailBackend):
|
||||||
|
|
||||||
init_parameters = {"token": {"label": "Token", "type": "password"},
|
init_parameters = {"token": {"label": "Token", "type": "password"},
|
||||||
"rooms": {"label": "Destination Rooms", "type": "list"},
|
"rooms": {"label": "Destination Rooms", "type": "list"},
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ import irc.client
|
|||||||
|
|
||||||
from django.utils.encoding import smart_text
|
from django.utils.encoding import smart_text
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from awx.main.notifications.base import TowerBaseEmailBackend
|
from awx.main.notifications.base import AWXBaseEmailBackend
|
||||||
|
|
||||||
logger = logging.getLogger('awx.main.notifications.irc_backend')
|
logger = logging.getLogger('awx.main.notifications.irc_backend')
|
||||||
|
|
||||||
|
|
||||||
class IrcBackend(TowerBaseEmailBackend):
|
class IrcBackend(AWXBaseEmailBackend):
|
||||||
|
|
||||||
init_parameters = {"server": {"label": "IRC Server Address", "type": "string"},
|
init_parameters = {"server": {"label": "IRC Server Address", "type": "string"},
|
||||||
"port": {"label": "IRC Server Port", "type": "int"},
|
"port": {"label": "IRC Server Port", "type": "int"},
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ import pygerduty
|
|||||||
|
|
||||||
from django.utils.encoding import smart_text
|
from django.utils.encoding import smart_text
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from awx.main.notifications.base import TowerBaseEmailBackend
|
from awx.main.notifications.base import AWXBaseEmailBackend
|
||||||
|
|
||||||
logger = logging.getLogger('awx.main.notifications.pagerduty_backend')
|
logger = logging.getLogger('awx.main.notifications.pagerduty_backend')
|
||||||
|
|
||||||
|
|
||||||
class PagerDutyBackend(TowerBaseEmailBackend):
|
class PagerDutyBackend(AWXBaseEmailBackend):
|
||||||
|
|
||||||
init_parameters = {"subdomain": {"label": "Pagerduty subdomain", "type": "string"},
|
init_parameters = {"subdomain": {"label": "Pagerduty subdomain", "type": "string"},
|
||||||
"token": {"label": "API Token", "type": "password"},
|
"token": {"label": "API Token", "type": "password"},
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ from slackclient import SlackClient
|
|||||||
|
|
||||||
from django.utils.encoding import smart_text
|
from django.utils.encoding import smart_text
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from awx.main.notifications.base import TowerBaseEmailBackend
|
from awx.main.notifications.base import AWXBaseEmailBackend
|
||||||
|
|
||||||
logger = logging.getLogger('awx.main.notifications.slack_backend')
|
logger = logging.getLogger('awx.main.notifications.slack_backend')
|
||||||
|
|
||||||
|
|
||||||
class SlackBackend(TowerBaseEmailBackend):
|
class SlackBackend(AWXBaseEmailBackend):
|
||||||
|
|
||||||
init_parameters = {"token": {"label": "Token", "type": "password"},
|
init_parameters = {"token": {"label": "Token", "type": "password"},
|
||||||
"channels": {"label": "Destination Channels", "type": "list"}}
|
"channels": {"label": "Destination Channels", "type": "list"}}
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ from twilio.rest import Client
|
|||||||
|
|
||||||
from django.utils.encoding import smart_text
|
from django.utils.encoding import smart_text
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from awx.main.notifications.base import TowerBaseEmailBackend
|
from awx.main.notifications.base import AWXBaseEmailBackend
|
||||||
|
|
||||||
logger = logging.getLogger('awx.main.notifications.twilio_backend')
|
logger = logging.getLogger('awx.main.notifications.twilio_backend')
|
||||||
|
|
||||||
|
|
||||||
class TwilioBackend(TowerBaseEmailBackend):
|
class TwilioBackend(AWXBaseEmailBackend):
|
||||||
|
|
||||||
init_parameters = {"account_sid": {"label": "Account SID", "type": "string"},
|
init_parameters = {"account_sid": {"label": "Account SID", "type": "string"},
|
||||||
"account_token": {"label": "Account Token", "type": "password"},
|
"account_token": {"label": "Account Token", "type": "password"},
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ import requests
|
|||||||
|
|
||||||
from django.utils.encoding import smart_text
|
from django.utils.encoding import smart_text
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from awx.main.notifications.base import TowerBaseEmailBackend
|
from awx.main.notifications.base import AWXBaseEmailBackend
|
||||||
from awx.main.utils import get_awx_version
|
from awx.main.utils import get_awx_version
|
||||||
|
|
||||||
logger = logging.getLogger('awx.main.notifications.webhook_backend')
|
logger = logging.getLogger('awx.main.notifications.webhook_backend')
|
||||||
|
|
||||||
|
|
||||||
class WebhookBackend(TowerBaseEmailBackend):
|
class WebhookBackend(AWXBaseEmailBackend):
|
||||||
|
|
||||||
init_parameters = {"url": {"label": "Target URL", "type": "string"},
|
init_parameters = {"url": {"label": "Target URL", "type": "string"},
|
||||||
"headers": {"label": "HTTP Headers", "type": "object"}}
|
"headers": {"label": "HTTP Headers", "type": "object"}}
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ class TaskManager():
|
|||||||
job.save(update_fields=['status', 'job_explanation'])
|
job.save(update_fields=['status', 'job_explanation'])
|
||||||
connection.on_commit(lambda: job.websocket_emit_status('failed'))
|
connection.on_commit(lambda: job.websocket_emit_status('failed'))
|
||||||
|
|
||||||
# TODO: should we emit a status on the socket here similar to tasks.py tower_periodic_scheduler() ?
|
# TODO: should we emit a status on the socket here similar to tasks.py awx_periodic_scheduler() ?
|
||||||
#emit_websocket_notification('/socket.io/jobs', '', dict(id=))
|
#emit_websocket_notification('/socket.io/jobs', '', dict(id=))
|
||||||
|
|
||||||
# See comment in tasks.py::RunWorkflowJob::run()
|
# See comment in tasks.py::RunWorkflowJob::run()
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ from django.core.cache import cache
|
|||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
from awx import __version__ as tower_application_version
|
from awx import __version__ as awx_application_version
|
||||||
from awx.main.constants import CLOUD_PROVIDERS, PRIVILEGE_ESCALATION_METHODS
|
from awx.main.constants import CLOUD_PROVIDERS, PRIVILEGE_ESCALATION_METHODS
|
||||||
from awx.main.models import * # noqa
|
from awx.main.models import * # noqa
|
||||||
from awx.main.models.unified_jobs import ACTIVE_STATES
|
from awx.main.models.unified_jobs import ACTIVE_STATES
|
||||||
@@ -188,7 +188,7 @@ def cluster_node_heartbeat(self):
|
|||||||
if inst.exists():
|
if inst.exists():
|
||||||
inst = inst[0]
|
inst = inst[0]
|
||||||
inst.capacity = get_system_task_capacity()
|
inst.capacity = get_system_task_capacity()
|
||||||
inst.version = tower_application_version
|
inst.version = awx_application_version
|
||||||
inst.save()
|
inst.save()
|
||||||
else:
|
else:
|
||||||
raise RuntimeError("Cluster Host Not Found: {}".format(settings.CLUSTER_HOST_ID))
|
raise RuntimeError("Cluster Host Not Found: {}".format(settings.CLUSTER_HOST_ID))
|
||||||
@@ -197,7 +197,7 @@ def cluster_node_heartbeat(self):
|
|||||||
for other_inst in recent_inst:
|
for other_inst in recent_inst:
|
||||||
if other_inst.version == "":
|
if other_inst.version == "":
|
||||||
continue
|
continue
|
||||||
if Version(other_inst.version.split('-', 1)[0]) > Version(tower_application_version) and not settings.DEBUG:
|
if Version(other_inst.version.split('-', 1)[0]) > Version(awx_application_version) and not settings.DEBUG:
|
||||||
logger.error("Host {} reports version {}, but this node {} is at {}, shutting down".format(other_inst.hostname,
|
logger.error("Host {} reports version {}, but this node {} is at {}, shutting down".format(other_inst.hostname,
|
||||||
other_inst.version,
|
other_inst.version,
|
||||||
inst.hostname,
|
inst.hostname,
|
||||||
@@ -213,7 +213,7 @@ def cluster_node_heartbeat(self):
|
|||||||
|
|
||||||
|
|
||||||
@task(bind=True, base=LogErrorsTask)
|
@task(bind=True, base=LogErrorsTask)
|
||||||
def tower_isolated_heartbeat(self):
|
def awx_isolated_heartbeat(self):
|
||||||
local_hostname = settings.CLUSTER_HOST_ID
|
local_hostname = settings.CLUSTER_HOST_ID
|
||||||
logger.debug("Controlling node checking for any isolated management tasks.")
|
logger.debug("Controlling node checking for any isolated management tasks.")
|
||||||
poll_interval = settings.AWX_ISOLATED_PERIODIC_CHECK
|
poll_interval = settings.AWX_ISOLATED_PERIODIC_CHECK
|
||||||
@@ -237,7 +237,7 @@ def tower_isolated_heartbeat(self):
|
|||||||
|
|
||||||
|
|
||||||
@task(bind=True, queue='tower', base=LogErrorsTask)
|
@task(bind=True, queue='tower', base=LogErrorsTask)
|
||||||
def tower_periodic_scheduler(self):
|
def awx_periodic_scheduler(self):
|
||||||
run_now = now()
|
run_now = now()
|
||||||
state = TowerScheduleState.get_solo()
|
state = TowerScheduleState.get_solo()
|
||||||
last_run = state.schedule_last_run
|
last_run = state.schedule_last_run
|
||||||
@@ -478,7 +478,7 @@ class BaseTask(LogErrorsTask):
|
|||||||
'''
|
'''
|
||||||
Create a temporary directory for job-related files.
|
Create a temporary directory for job-related files.
|
||||||
'''
|
'''
|
||||||
path = tempfile.mkdtemp(prefix='ansible_awx_%s_' % instance.pk, dir=settings.AWX_PROOT_BASE_PATH)
|
path = tempfile.mkdtemp(prefix='awx_%s_' % instance.pk, dir=settings.AWX_PROOT_BASE_PATH)
|
||||||
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
|
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
|
||||||
self.cleanup_paths.append(path)
|
self.cleanup_paths.append(path)
|
||||||
return path
|
return path
|
||||||
@@ -541,7 +541,7 @@ class BaseTask(LogErrorsTask):
|
|||||||
'': '',
|
'': '',
|
||||||
}
|
}
|
||||||
|
|
||||||
def add_ansible_venv(self, env, add_tower_lib=True):
|
def add_ansible_venv(self, env, add_awx_lib=True):
|
||||||
env['VIRTUAL_ENV'] = settings.ANSIBLE_VENV_PATH
|
env['VIRTUAL_ENV'] = settings.ANSIBLE_VENV_PATH
|
||||||
env['PATH'] = os.path.join(settings.ANSIBLE_VENV_PATH, "bin") + ":" + env['PATH']
|
env['PATH'] = os.path.join(settings.ANSIBLE_VENV_PATH, "bin") + ":" + env['PATH']
|
||||||
venv_libdir = os.path.join(settings.ANSIBLE_VENV_PATH, "lib")
|
venv_libdir = os.path.join(settings.ANSIBLE_VENV_PATH, "lib")
|
||||||
@@ -551,11 +551,11 @@ class BaseTask(LogErrorsTask):
|
|||||||
env['PYTHONPATH'] = os.path.join(venv_libdir, python_ver, "site-packages") + ":"
|
env['PYTHONPATH'] = os.path.join(venv_libdir, python_ver, "site-packages") + ":"
|
||||||
break
|
break
|
||||||
# Add awx/lib to PYTHONPATH.
|
# Add awx/lib to PYTHONPATH.
|
||||||
if add_tower_lib:
|
if add_awx_lib:
|
||||||
env['PYTHONPATH'] = env.get('PYTHONPATH', '') + self.get_path_to('..', 'lib') + ':'
|
env['PYTHONPATH'] = env.get('PYTHONPATH', '') + self.get_path_to('..', 'lib') + ':'
|
||||||
return env
|
return env
|
||||||
|
|
||||||
def add_tower_venv(self, env):
|
def add_awx_venv(self, env):
|
||||||
env['VIRTUAL_ENV'] = settings.AWX_VENV_PATH
|
env['VIRTUAL_ENV'] = settings.AWX_VENV_PATH
|
||||||
env['PATH'] = os.path.join(settings.AWX_VENV_PATH, "bin") + ":" + env['PATH']
|
env['PATH'] = os.path.join(settings.AWX_VENV_PATH, "bin") + ":" + env['PATH']
|
||||||
return env
|
return env
|
||||||
@@ -576,7 +576,7 @@ class BaseTask(LogErrorsTask):
|
|||||||
# callbacks to work.
|
# callbacks to work.
|
||||||
# Update PYTHONPATH to use local site-packages.
|
# Update PYTHONPATH to use local site-packages.
|
||||||
# NOTE:
|
# NOTE:
|
||||||
# Derived class should call add_ansible_venv() or add_tower_venv()
|
# Derived class should call add_ansible_venv() or add_awx_venv()
|
||||||
if self.should_use_proot(instance, **kwargs):
|
if self.should_use_proot(instance, **kwargs):
|
||||||
env['PROOT_TMP_DIR'] = settings.AWX_PROOT_BASE_PATH
|
env['PROOT_TMP_DIR'] = settings.AWX_PROOT_BASE_PATH
|
||||||
return env
|
return env
|
||||||
@@ -612,7 +612,7 @@ class BaseTask(LogErrorsTask):
|
|||||||
# For isolated jobs, we have to interact w/ the REST API from the
|
# For isolated jobs, we have to interact w/ the REST API from the
|
||||||
# controlling node and ship the static JSON inventory to the
|
# controlling node and ship the static JSON inventory to the
|
||||||
# isolated host (because the isolated host itself can't reach the
|
# isolated host (because the isolated host itself can't reach the
|
||||||
# Tower REST API to fetch the inventory).
|
# REST API to fetch the inventory).
|
||||||
path = os.path.join(kwargs['private_data_dir'], 'inventory')
|
path = os.path.join(kwargs['private_data_dir'], 'inventory')
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
return path
|
return path
|
||||||
@@ -932,7 +932,7 @@ class RunJob(BaseTask):
|
|||||||
plugin_dirs.extend(settings.AWX_ANSIBLE_CALLBACK_PLUGINS)
|
plugin_dirs.extend(settings.AWX_ANSIBLE_CALLBACK_PLUGINS)
|
||||||
plugin_path = ':'.join(plugin_dirs)
|
plugin_path = ':'.join(plugin_dirs)
|
||||||
env = super(RunJob, self).build_env(job, **kwargs)
|
env = super(RunJob, self).build_env(job, **kwargs)
|
||||||
env = self.add_ansible_venv(env, add_tower_lib=kwargs.get('isolated', False))
|
env = self.add_ansible_venv(env, add_awx_lib=kwargs.get('isolated', False))
|
||||||
# Set environment variables needed for inventory and job event
|
# Set environment variables needed for inventory and job event
|
||||||
# callbacks to work.
|
# callbacks to work.
|
||||||
env['JOB_ID'] = str(job.pk)
|
env['JOB_ID'] = str(job.pk)
|
||||||
@@ -940,7 +940,7 @@ class RunJob(BaseTask):
|
|||||||
if job.use_fact_cache and not kwargs.get('isolated'):
|
if job.use_fact_cache and not kwargs.get('isolated'):
|
||||||
env['ANSIBLE_LIBRARY'] = self.get_path_to('..', 'plugins', 'library')
|
env['ANSIBLE_LIBRARY'] = self.get_path_to('..', 'plugins', 'library')
|
||||||
env['ANSIBLE_CACHE_PLUGINS'] = self.get_path_to('..', 'plugins', 'fact_caching')
|
env['ANSIBLE_CACHE_PLUGINS'] = self.get_path_to('..', 'plugins', 'fact_caching')
|
||||||
env['ANSIBLE_CACHE_PLUGIN'] = "tower"
|
env['ANSIBLE_CACHE_PLUGIN'] = "awx"
|
||||||
env['ANSIBLE_FACT_CACHE_TIMEOUT'] = str(settings.ANSIBLE_FACT_CACHE_TIMEOUT)
|
env['ANSIBLE_FACT_CACHE_TIMEOUT'] = str(settings.ANSIBLE_FACT_CACHE_TIMEOUT)
|
||||||
env['ANSIBLE_CACHE_PLUGIN_CONNECTION'] = settings.CACHES['default']['LOCATION'] if 'LOCATION' in settings.CACHES['default'] else ''
|
env['ANSIBLE_CACHE_PLUGIN_CONNECTION'] = settings.CACHES['default']['LOCATION'] if 'LOCATION' in settings.CACHES['default'] else ''
|
||||||
if job.project:
|
if job.project:
|
||||||
@@ -949,10 +949,11 @@ class RunJob(BaseTask):
|
|||||||
env['MAX_EVENT_RES'] = str(settings.MAX_EVENT_RES_DATA)
|
env['MAX_EVENT_RES'] = str(settings.MAX_EVENT_RES_DATA)
|
||||||
if not kwargs.get('isolated'):
|
if not kwargs.get('isolated'):
|
||||||
env['ANSIBLE_CALLBACK_PLUGINS'] = plugin_path
|
env['ANSIBLE_CALLBACK_PLUGINS'] = plugin_path
|
||||||
env['ANSIBLE_STDOUT_CALLBACK'] = 'tower_display'
|
env['ANSIBLE_STDOUT_CALLBACK'] = 'awx_display'
|
||||||
env['REST_API_URL'] = settings.INTERNAL_API_URL
|
env['REST_API_URL'] = settings.INTERNAL_API_URL
|
||||||
env['REST_API_TOKEN'] = job.task_auth_token or ''
|
env['REST_API_TOKEN'] = job.task_auth_token or ''
|
||||||
env['TOWER_HOST'] = settings.TOWER_URL_BASE
|
env['TOWER_HOST'] = settings.TOWER_URL_BASE
|
||||||
|
env['AWX_HOST'] = settings.TOWER_URL_BASE
|
||||||
env['CALLBACK_QUEUE'] = settings.CALLBACK_QUEUE
|
env['CALLBACK_QUEUE'] = settings.CALLBACK_QUEUE
|
||||||
env['CALLBACK_CONNECTION'] = settings.BROKER_URL
|
env['CALLBACK_CONNECTION'] = settings.BROKER_URL
|
||||||
env['CACHE'] = settings.CACHES['default']['LOCATION'] if 'LOCATION' in settings.CACHES['default'] else ''
|
env['CACHE'] = settings.CACHES['default']['LOCATION'] if 'LOCATION' in settings.CACHES['default'] else ''
|
||||||
@@ -1073,24 +1074,31 @@ class RunJob(BaseTask):
|
|||||||
if job.start_at_task:
|
if job.start_at_task:
|
||||||
args.append('--start-at-task=%s' % job.start_at_task)
|
args.append('--start-at-task=%s' % job.start_at_task)
|
||||||
|
|
||||||
# Define special extra_vars for Tower, combine with job.extra_vars.
|
# Define special extra_vars for AWX, combine with job.extra_vars.
|
||||||
extra_vars = {
|
extra_vars = {
|
||||||
'tower_job_id': job.pk,
|
'tower_job_id': job.pk,
|
||||||
'tower_job_launch_type': job.launch_type,
|
'tower_job_launch_type': job.launch_type,
|
||||||
|
'awx_job_id': job.pk,
|
||||||
|
'awx_job_launch_type': job.launch_type,
|
||||||
}
|
}
|
||||||
if job.project:
|
if job.project:
|
||||||
extra_vars.update({
|
extra_vars.update({
|
||||||
'tower_project_revision': job.project.scm_revision,
|
'tower_project_revision': job.project.scm_revision,
|
||||||
|
'awx_project_revision': job.project.scm_revision,
|
||||||
})
|
})
|
||||||
if job.job_template:
|
if job.job_template:
|
||||||
extra_vars.update({
|
extra_vars.update({
|
||||||
'tower_job_template_id': job.job_template.pk,
|
'tower_job_template_id': job.job_template.pk,
|
||||||
'tower_job_template_name': job.job_template.name,
|
'tower_job_template_name': job.job_template.name,
|
||||||
|
'awx_job_template_id': job.job_template.pk,
|
||||||
|
'awx_job_template_name': job.job_template.name,
|
||||||
})
|
})
|
||||||
if job.created_by:
|
if job.created_by:
|
||||||
extra_vars.update({
|
extra_vars.update({
|
||||||
'tower_user_id': job.created_by.pk,
|
'tower_user_id': job.created_by.pk,
|
||||||
'tower_user_name': job.created_by.username,
|
'tower_user_name': job.created_by.username,
|
||||||
|
'awx_user_id': job.created_by.pk,
|
||||||
|
'awx_user_name': job.created_by.username,
|
||||||
})
|
})
|
||||||
if job.extra_vars_dict:
|
if job.extra_vars_dict:
|
||||||
if kwargs.get('display', False) and job.job_template:
|
if kwargs.get('display', False) and job.job_template:
|
||||||
@@ -1738,7 +1746,7 @@ class RunInventoryUpdate(BaseTask):
|
|||||||
"""
|
"""
|
||||||
env = super(RunInventoryUpdate, self).build_env(inventory_update,
|
env = super(RunInventoryUpdate, self).build_env(inventory_update,
|
||||||
**kwargs)
|
**kwargs)
|
||||||
env = self.add_tower_venv(env)
|
env = self.add_awx_venv(env)
|
||||||
# Pass inventory source ID to inventory script.
|
# Pass inventory source ID to inventory script.
|
||||||
env['INVENTORY_SOURCE_ID'] = str(inventory_update.inventory_source_id)
|
env['INVENTORY_SOURCE_ID'] = str(inventory_update.inventory_source_id)
|
||||||
env['INVENTORY_UPDATE_ID'] = str(inventory_update.pk)
|
env['INVENTORY_UPDATE_ID'] = str(inventory_update.pk)
|
||||||
@@ -1748,7 +1756,7 @@ class RunInventoryUpdate(BaseTask):
|
|||||||
# These are set here and then read in by the various Ansible inventory
|
# These are set here and then read in by the various Ansible inventory
|
||||||
# modules, which will actually do the inventory sync.
|
# modules, which will actually do the inventory sync.
|
||||||
#
|
#
|
||||||
# The inventory modules are vendored in Tower in the
|
# The inventory modules are vendored in AWX in the
|
||||||
# `awx/plugins/inventory` directory; those files should be kept in
|
# `awx/plugins/inventory` directory; those files should be kept in
|
||||||
# sync with those in Ansible core at all times.
|
# sync with those in Ansible core at all times.
|
||||||
passwords = kwargs.get('passwords', {})
|
passwords = kwargs.get('passwords', {})
|
||||||
@@ -1820,9 +1828,9 @@ class RunInventoryUpdate(BaseTask):
|
|||||||
src = inventory_update.source
|
src = inventory_update.source
|
||||||
|
|
||||||
# Add several options to the shell arguments based on the
|
# Add several options to the shell arguments based on the
|
||||||
# inventory-source-specific setting in the Tower configuration.
|
# inventory-source-specific setting in the AWX configuration.
|
||||||
# These settings are "per-source"; it's entirely possible that
|
# These settings are "per-source"; it's entirely possible that
|
||||||
# they will be different between cloud providers if a Tower user
|
# they will be different between cloud providers if an AWX user
|
||||||
# actively uses more than one.
|
# actively uses more than one.
|
||||||
if getattr(settings, '%s_ENABLED_VAR' % src.upper(), False):
|
if getattr(settings, '%s_ENABLED_VAR' % src.upper(), False):
|
||||||
args.extend(['--enabled-var',
|
args.extend(['--enabled-var',
|
||||||
@@ -1852,7 +1860,7 @@ class RunInventoryUpdate(BaseTask):
|
|||||||
elif src == 'scm':
|
elif src == 'scm':
|
||||||
args.append(inventory_update.get_actual_source_path())
|
args.append(inventory_update.get_actual_source_path())
|
||||||
elif src == 'custom':
|
elif src == 'custom':
|
||||||
runpath = tempfile.mkdtemp(prefix='ansible_awx_inventory_', dir=settings.AWX_PROOT_BASE_PATH)
|
runpath = tempfile.mkdtemp(prefix='awx_inventory_', dir=settings.AWX_PROOT_BASE_PATH)
|
||||||
handle, path = tempfile.mkstemp(dir=runpath)
|
handle, path = tempfile.mkstemp(dir=runpath)
|
||||||
f = os.fdopen(handle, 'w')
|
f = os.fdopen(handle, 'w')
|
||||||
if inventory_update.source_script is None:
|
if inventory_update.source_script is None:
|
||||||
@@ -2139,7 +2147,7 @@ class RunSystemJob(BaseTask):
|
|||||||
def build_env(self, instance, **kwargs):
|
def build_env(self, instance, **kwargs):
|
||||||
env = super(RunSystemJob, self).build_env(instance,
|
env = super(RunSystemJob, self).build_env(instance,
|
||||||
**kwargs)
|
**kwargs)
|
||||||
env = self.add_tower_venv(env)
|
env = self.add_awx_venv(env)
|
||||||
return env
|
return env
|
||||||
|
|
||||||
def build_cwd(self, instance, **kwargs):
|
def build_cwd(self, instance, **kwargs):
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from django.utils.timezone import now, timedelta
|
|||||||
|
|
||||||
from awx.main.tasks import (
|
from awx.main.tasks import (
|
||||||
RunProjectUpdate, RunInventoryUpdate,
|
RunProjectUpdate, RunInventoryUpdate,
|
||||||
tower_isolated_heartbeat,
|
awx_isolated_heartbeat,
|
||||||
isolated_manager
|
isolated_manager
|
||||||
)
|
)
|
||||||
from awx.main.models import (
|
from awx.main.models import (
|
||||||
@@ -121,7 +121,7 @@ class TestIsolatedManagementTask:
|
|||||||
original_isolated_instance = needs_updating.instances.all().first()
|
original_isolated_instance = needs_updating.instances.all().first()
|
||||||
with mock.patch('awx.main.tasks.settings', MockSettings()):
|
with mock.patch('awx.main.tasks.settings', MockSettings()):
|
||||||
with mock.patch.object(isolated_manager.IsolatedManager, 'health_check') as check_mock:
|
with mock.patch.object(isolated_manager.IsolatedManager, 'health_check') as check_mock:
|
||||||
tower_isolated_heartbeat()
|
awx_isolated_heartbeat()
|
||||||
iso_instance = Instance.objects.get(hostname='isolated')
|
iso_instance = Instance.objects.get(hostname='isolated')
|
||||||
call_args, _ = check_mock.call_args
|
call_args, _ = check_mock.call_args
|
||||||
assert call_args[0][0] == iso_instance
|
assert call_args[0][0] == iso_instance
|
||||||
@@ -131,7 +131,7 @@ class TestIsolatedManagementTask:
|
|||||||
def test_does_not_take_action(self, control_instance, just_updated):
|
def test_does_not_take_action(self, control_instance, just_updated):
|
||||||
with mock.patch('awx.main.tasks.settings', MockSettings()):
|
with mock.patch('awx.main.tasks.settings', MockSettings()):
|
||||||
with mock.patch.object(isolated_manager.IsolatedManager, 'health_check') as check_mock:
|
with mock.patch.object(isolated_manager.IsolatedManager, 'health_check') as check_mock:
|
||||||
tower_isolated_heartbeat()
|
awx_isolated_heartbeat()
|
||||||
iso_instance = Instance.objects.get(hostname='isolated')
|
iso_instance = Instance.objects.get(hostname='isolated')
|
||||||
check_mock.assert_not_called()
|
check_mock.assert_not_called()
|
||||||
assert iso_instance.capacity == 103
|
assert iso_instance.capacity == 103
|
||||||
|
|||||||
@@ -37,10 +37,10 @@ class BaseJobTestMixin(BaseTestMixin):
|
|||||||
return inventory
|
return inventory
|
||||||
|
|
||||||
def populate(self):
|
def populate(self):
|
||||||
# Here's a little story about the Ansible Bread Company, or ABC. They
|
# Here's a little story about the AWX Bread Company, or ABC. They
|
||||||
# make machines that make bread - bakers, slicers, and packagers - and
|
# make machines that make bread - bakers, slicers, and packagers - and
|
||||||
# these machines are each controlled by a Linux boxes, which is in turn
|
# these machines are each controlled by a Linux boxes, which is in turn
|
||||||
# managed by Ansible Commander.
|
# managed by AWX.
|
||||||
|
|
||||||
# Sue is the super user. You don't mess with Sue or you're toast. Ha.
|
# Sue is the super user. You don't mess with Sue or you're toast. Ha.
|
||||||
self.user_sue = self.make_user('sue', super_user=True)
|
self.user_sue = self.make_user('sue', super_user=True)
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ def test_run_isolated_job(private_data_dir, rsa_key):
|
|||||||
assert FILENAME in stdout.getvalue()
|
assert FILENAME in stdout.getvalue()
|
||||||
|
|
||||||
assert '/path/to/awx/lib' in env['PYTHONPATH']
|
assert '/path/to/awx/lib' in env['PYTHONPATH']
|
||||||
assert env['ANSIBLE_STDOUT_CALLBACK'] == 'tower_display'
|
assert env['ANSIBLE_STDOUT_CALLBACK'] == 'awx_display'
|
||||||
assert env['ANSIBLE_CALLBACK_PLUGINS'] == '/path/to/awx/lib/isolated_callbacks'
|
assert env['ANSIBLE_CALLBACK_PLUGINS'] == '/path/to/awx/lib/isolated_callbacks'
|
||||||
assert env['AWX_ISOLATED_DATA_DIR'] == private_data_dir
|
assert env['AWX_ISOLATED_DATA_DIR'] == private_data_dir
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from datetime import timedelta
|
|||||||
|
|
||||||
@pytest.mark.parametrize("job_name,function_path", [
|
@pytest.mark.parametrize("job_name,function_path", [
|
||||||
('admin_checks', 'awx.main.tasks.run_administrative_checks'),
|
('admin_checks', 'awx.main.tasks.run_administrative_checks'),
|
||||||
('tower_scheduler', 'awx.main.tasks.tower_periodic_scheduler'),
|
('tower_scheduler', 'awx.main.tasks.awx_periodic_scheduler'),
|
||||||
])
|
])
|
||||||
def test_CELERYBEAT_SCHEDULE(mocker, job_name, function_path):
|
def test_CELERYBEAT_SCHEDULE(mocker, job_name, function_path):
|
||||||
assert job_name in settings.CELERYBEAT_SCHEDULE
|
assert job_name in settings.CELERYBEAT_SCHEDULE
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ class TestJobExecution:
|
|||||||
EXAMPLE_PRIVATE_KEY = '-----BEGIN PRIVATE KEY-----\nxyz==\n-----END PRIVATE KEY-----'
|
EXAMPLE_PRIVATE_KEY = '-----BEGIN PRIVATE KEY-----\nxyz==\n-----END PRIVATE KEY-----'
|
||||||
|
|
||||||
def setup_method(self, method):
|
def setup_method(self, method):
|
||||||
self.project_path = tempfile.mkdtemp(prefix='ansible_awx_project_')
|
self.project_path = tempfile.mkdtemp(prefix='awx_project_')
|
||||||
with open(os.path.join(self.project_path, 'helloworld.yml'), 'w') as f:
|
with open(os.path.join(self.project_path, 'helloworld.yml'), 'w') as f:
|
||||||
f.write('---')
|
f.write('---')
|
||||||
|
|
||||||
@@ -312,7 +312,7 @@ class TestIsolatedExecution(TestJobExecution):
|
|||||||
credential.inputs['password'] = encrypt_field(credential, 'password')
|
credential.inputs['password'] = encrypt_field(credential, 'password')
|
||||||
self.instance.credential = credential
|
self.instance.credential = credential
|
||||||
|
|
||||||
private_data = tempfile.mkdtemp(prefix='ansible_awx_')
|
private_data = tempfile.mkdtemp(prefix='awx_')
|
||||||
self.task.build_private_data_dir = mock.Mock(return_value=private_data)
|
self.task.build_private_data_dir = mock.Mock(return_value=private_data)
|
||||||
inventory = json.dumps({"all": {"hosts": ["localhost"]}})
|
inventory = json.dumps({"all": {"hosts": ["localhost"]}})
|
||||||
|
|
||||||
@@ -351,7 +351,7 @@ class TestIsolatedExecution(TestJobExecution):
|
|||||||
extra_vars = json.loads(extra_vars)
|
extra_vars = json.loads(extra_vars)
|
||||||
assert extra_vars['dest'] == '/tmp'
|
assert extra_vars['dest'] == '/tmp'
|
||||||
assert extra_vars['src'] == private_data
|
assert extra_vars['src'] == private_data
|
||||||
assert extra_vars['proot_temp_dir'].startswith('/tmp/ansible_awx_proot_')
|
assert extra_vars['proot_temp_dir'].startswith('/tmp/awx_proot_')
|
||||||
|
|
||||||
def test_systemctl_failure(self):
|
def test_systemctl_failure(self):
|
||||||
# If systemctl fails, read the contents of `artifacts/systemctl_logs`
|
# If systemctl fails, read the contents of `artifacts/systemctl_logs`
|
||||||
@@ -364,7 +364,7 @@ class TestIsolatedExecution(TestJobExecution):
|
|||||||
)
|
)
|
||||||
self.instance.credential = credential
|
self.instance.credential = credential
|
||||||
|
|
||||||
private_data = tempfile.mkdtemp(prefix='ansible_awx_')
|
private_data = tempfile.mkdtemp(prefix='awx_')
|
||||||
self.task.build_private_data_dir = mock.Mock(return_value=private_data)
|
self.task.build_private_data_dir = mock.Mock(return_value=private_data)
|
||||||
inventory = json.dumps({"all": {"hosts": ["localhost"]}})
|
inventory = json.dumps({"all": {"hosts": ["localhost"]}})
|
||||||
|
|
||||||
@@ -464,7 +464,7 @@ class TestJobCredentials(TestJobExecution):
|
|||||||
)
|
)
|
||||||
return ['successful', 0]
|
return ['successful', 0]
|
||||||
|
|
||||||
private_data = tempfile.mkdtemp(prefix='ansible_awx_')
|
private_data = tempfile.mkdtemp(prefix='awx_')
|
||||||
self.task.build_private_data_dir = mock.Mock(return_value=private_data)
|
self.task.build_private_data_dir = mock.Mock(return_value=private_data)
|
||||||
self.run_pexpect.side_effect = partial(run_pexpect_side_effect, private_data)
|
self.run_pexpect.side_effect = partial(run_pexpect_side_effect, private_data)
|
||||||
self.task.run(self.pk, private_data_dir=private_data)
|
self.task.run(self.pk, private_data_dir=private_data)
|
||||||
@@ -1145,7 +1145,7 @@ class TestProjectUpdateCredentials(TestJobExecution):
|
|||||||
assert 'bob' in kwargs.get('expect_passwords').values()
|
assert 'bob' in kwargs.get('expect_passwords').values()
|
||||||
return ['successful', 0]
|
return ['successful', 0]
|
||||||
|
|
||||||
private_data = tempfile.mkdtemp(prefix='ansible_awx_')
|
private_data = tempfile.mkdtemp(prefix='awx_')
|
||||||
self.task.build_private_data_dir = mock.Mock(return_value=private_data)
|
self.task.build_private_data_dir = mock.Mock(return_value=private_data)
|
||||||
self.run_pexpect.side_effect = partial(run_pexpect_side_effect, private_data)
|
self.run_pexpect.side_effect = partial(run_pexpect_side_effect, private_data)
|
||||||
self.task.run(self.pk)
|
self.task.run(self.pk)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2017 Ansible Tower by Red Hat
|
# Copyright (c) 2017 Ansible by Red Hat
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
# AWX
|
# AWX
|
||||||
|
|||||||
@@ -152,12 +152,12 @@ def get_ssh_version():
|
|||||||
|
|
||||||
def get_awx_version():
|
def get_awx_version():
|
||||||
'''
|
'''
|
||||||
Return Ansible Tower version as reported by setuptools.
|
Return AWX version as reported by setuptools.
|
||||||
'''
|
'''
|
||||||
from awx import __version__
|
from awx import __version__
|
||||||
try:
|
try:
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
return pkg_resources.require('ansible-awx')[0].version
|
return pkg_resources.require('awx')[0].version
|
||||||
except:
|
except:
|
||||||
return __version__
|
return __version__
|
||||||
|
|
||||||
@@ -655,7 +655,7 @@ def build_proot_temp_dir():
|
|||||||
Create a temporary directory for proot to use.
|
Create a temporary directory for proot to use.
|
||||||
'''
|
'''
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
path = tempfile.mkdtemp(prefix='ansible_awx_proot_', dir=settings.AWX_PROOT_BASE_PATH)
|
path = tempfile.mkdtemp(prefix='awx_proot_', dir=settings.AWX_PROOT_BASE_PATH)
|
||||||
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
|
os.chmod(path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
|
||||||
return path
|
return path
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2017 Ansible Tower by Red Hat
|
# Copyright (c) 2017 Ansible by Red Hat
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
# Python
|
# Python
|
||||||
@@ -134,7 +134,7 @@ class BaseHandler(logging.Handler):
|
|||||||
# Don't send handler-related records.
|
# Don't send handler-related records.
|
||||||
if logger_name == logger.name:
|
if logger_name == logger.name:
|
||||||
return True
|
return True
|
||||||
# Tower log emission is only turned off by enablement setting
|
# AWX log emission is only turned off by enablement setting
|
||||||
if not logger_name.startswith('awx.analytics'):
|
if not logger_name.startswith('awx.analytics'):
|
||||||
return False
|
return False
|
||||||
return self.enabled_loggers is None or logger_name[len('awx.analytics.'):] not in self.enabled_loggers
|
return self.enabled_loggers is None or logger_name[len('awx.analytics.'):] not in self.enabled_loggers
|
||||||
@@ -216,7 +216,7 @@ class BaseHTTPSHandler(BaseHandler):
|
|||||||
logger = logging.getLogger(__file__)
|
logger = logging.getLogger(__file__)
|
||||||
fn, lno, func = logger.findCaller()
|
fn, lno, func = logger.findCaller()
|
||||||
record = logger.makeRecord('awx', 10, fn, lno,
|
record = logger.makeRecord('awx', 10, fn, lno,
|
||||||
'Ansible Tower Connection Test', tuple(),
|
'AWX Connection Test', tuple(),
|
||||||
None, func)
|
None, func)
|
||||||
futures = handler.emit(record)
|
futures = handler.emit(record)
|
||||||
for future in futures:
|
for future in futures:
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ class MemHost(MemObject):
|
|||||||
self.instance_id = None
|
self.instance_id = None
|
||||||
self.name = name
|
self.name = name
|
||||||
if port:
|
if port:
|
||||||
# was `ansible_ssh_port` in older Ansible/Tower versions
|
# was `ansible_ssh_port` in older Ansible versions
|
||||||
self.variables['ansible_port'] = port
|
self.variables['ansible_port'] = port
|
||||||
logger.debug('Loaded host: %s', self.name)
|
logger.debug('Loaded host: %s', self.name)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Copyright (c) 2017 Ansible Tower by Red Hat
|
# Copyright (c) 2017 Ansible by Red Hat
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
|
|
||||||
# Python
|
# Python
|
||||||
|
|||||||
@@ -27,4 +27,4 @@ if awx_lib_path not in sys.path:
|
|||||||
sys.path.insert(0, awx_lib_path)
|
sys.path.insert(0, awx_lib_path)
|
||||||
|
|
||||||
# Tower Display Callback
|
# Tower Display Callback
|
||||||
from tower_display_callback import TowerDefaultCallbackModule as CallbackModule # noqa
|
from awx_display_callback import AWXDefaultCallbackModule as CallbackModule # noqa
|
||||||
@@ -27,4 +27,4 @@ if awx_lib_path not in sys.path:
|
|||||||
sys.path.insert(0, awx_lib_path)
|
sys.path.insert(0, awx_lib_path)
|
||||||
|
|
||||||
# Tower Display Callback
|
# Tower Display Callback
|
||||||
from tower_display_callback import TowerMinimalCallbackModule as CallbackModule # noqa
|
from awx_display_callback import AWXMinimalCallbackModule as CallbackModule # noqa
|
||||||
|
|||||||
@@ -448,7 +448,7 @@ CELERY_ROUTES = {'awx.main.scheduler.tasks.run_task_manager': {'queue': 'tower',
|
|||||||
|
|
||||||
CELERYBEAT_SCHEDULE = {
|
CELERYBEAT_SCHEDULE = {
|
||||||
'tower_scheduler': {
|
'tower_scheduler': {
|
||||||
'task': 'awx.main.tasks.tower_periodic_scheduler',
|
'task': 'awx.main.tasks.awx_periodic_scheduler',
|
||||||
'schedule': timedelta(seconds=30),
|
'schedule': timedelta(seconds=30),
|
||||||
'options': {'expires': 20,}
|
'options': {'expires': 20,}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ CELERY_ROUTES['awx.main.tasks.cluster_node_heartbeat'] = {'queue': CLUSTER_HOST_
|
|||||||
# Production only runs this schedule on controlling nodes
|
# Production only runs this schedule on controlling nodes
|
||||||
# but development will just run it on all nodes
|
# but development will just run it on all nodes
|
||||||
CELERYBEAT_SCHEDULE['isolated_heartbeat'] = {
|
CELERYBEAT_SCHEDULE['isolated_heartbeat'] = {
|
||||||
'task': 'awx.main.tasks.tower_isolated_heartbeat',
|
'task': 'awx.main.tasks.awx_isolated_heartbeat',
|
||||||
'schedule': timedelta(seconds = AWX_ISOLATED_PERIODIC_CHECK),
|
'schedule': timedelta(seconds = AWX_ISOLATED_PERIODIC_CHECK),
|
||||||
'options': {'expires': AWX_ISOLATED_PERIODIC_CHECK * 2,}
|
'options': {'expires': AWX_ISOLATED_PERIODIC_CHECK * 2,}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ from django.utils.encoding import smart_text
|
|||||||
# Django REST Framework
|
# Django REST Framework
|
||||||
from rest_framework.renderers import JSONRenderer
|
from rest_framework.renderers import JSONRenderer
|
||||||
|
|
||||||
# Ansible Tower
|
# AWX
|
||||||
from awx.main.models import AuthToken
|
from awx.main.models import AuthToken
|
||||||
from awx.api.serializers import UserSerializer
|
from awx.api.serializers import UserSerializer
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{% extends "rest_framework/api.html" %}
|
{% extends "rest_framework/api.html" %}
|
||||||
{% load i18n staticfiles %}
|
{% load i18n staticfiles %}
|
||||||
|
|
||||||
{% block title %}{{ name }} · {% trans 'Ansible Tower' %}{% endblock %}
|
{% block title %}{{ name }} · {% trans 'AWX' %}{% endblock %}
|
||||||
|
|
||||||
{% block style %}
|
{% block style %}
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{% extends 'rest_framework/base.html' %}
|
{% extends 'rest_framework/base.html' %}
|
||||||
{% load i18n staticfiles %}
|
{% load i18n staticfiles %}
|
||||||
|
|
||||||
{% block title %}{{ name }} · {% trans 'Ansible Tower REST API' %}{% endblock %}
|
{% block title %}{{ name }} · {% trans 'AWX REST API' %}{% endblock %}
|
||||||
|
|
||||||
{% block bootstrap_theme %}
|
{% block bootstrap_theme %}
|
||||||
<link rel="stylesheet" type="text/css" href="{% static 'rest_framework/css/bootstrap.min.css' %}" />
|
<link rel="stylesheet" type="text/css" href="{% static 'rest_framework/css/bootstrap.min.css' %}" />
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
{# Copy of base.html from rest_framework with minor Ansible Tower change. #}
|
{# Copy of base.html from rest_framework with minor AWX change. #}
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
{% load rest_framework %}
|
{% load rest_framework %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|||||||
6
setup.py
6
setup.py
@@ -123,12 +123,12 @@ def proc_data_files(data_files):
|
|||||||
|
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name=os.getenv('NAME', 'ansible-awx'),
|
name=os.getenv('NAME', 'awx'),
|
||||||
version=get_version(),
|
version=get_version(),
|
||||||
author='Ansible, Inc.',
|
author='Ansible, Inc.',
|
||||||
author_email='info@ansible.com',
|
author_email='info@ansible.com',
|
||||||
description='ansible-awx: API, UI and Task Engine for Ansible',
|
description='awx: API, UI and Task Engine for Ansible',
|
||||||
long_description='Ansible AWX provides a web-based user interface, REST API and '
|
long_description='AWX provides a web-based user interface, REST API and '
|
||||||
'task engine built on top of Ansible',
|
'task engine built on top of Ansible',
|
||||||
license='MIT',
|
license='MIT',
|
||||||
keywords='ansible',
|
keywords='ansible',
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ RUN /usr/bin/ssh-keygen -q -t rsa -N "" -f /root/.ssh/id_rsa
|
|||||||
RUN mkdir -p /data/db
|
RUN mkdir -p /data/db
|
||||||
RUN pip2 install honcho
|
RUN pip2 install honcho
|
||||||
RUN pip2 install supervisor
|
RUN pip2 install supervisor
|
||||||
ADD tools/docker-compose/ansible-awx.egg-link /tmp/ansible-awx.egg-link
|
ADD tools/docker-compose/awx.egg-link /tmp/awx.egg-link
|
||||||
ADD tools/docker-compose/awx-manage /usr/local/bin/awx-manage
|
ADD tools/docker-compose/awx-manage /usr/local/bin/awx-manage
|
||||||
ADD tools/docker-compose/ansible_awx.egg-info /tmp/ansible_awx.egg-info
|
ADD tools/docker-compose/awx.egg-info /tmp/awx.egg-info
|
||||||
RUN ln -Ffs /awx_devel/tools/docker-compose/nginx.conf /etc/nginx/nginx.conf
|
RUN ln -Ffs /awx_devel/tools/docker-compose/nginx.conf /etc/nginx/nginx.conf
|
||||||
RUN ln -Ffs /awx_devel/tools/docker-compose/nginx.vh.default.conf /etc/nginx/conf.d/nginx.vh.default.conf
|
RUN ln -Ffs /awx_devel/tools/docker-compose/nginx.vh.default.conf /etc/nginx/conf.d/nginx.vh.default.conf
|
||||||
RUN ln -s /awx_devel/tools/docker-compose/start_development.sh /start_development.sh
|
RUN ln -s /awx_devel/tools/docker-compose/start_development.sh /start_development.sh
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#!/venv/awx/bin/python
|
#!/venv/awx/bin/python
|
||||||
# EASY-INSTALL-ENTRY-SCRIPT: 'ansible-awx','console_scripts','awx-manage'
|
# EASY-INSTALL-ENTRY-SCRIPT: 'awx','console_scripts','awx-manage'
|
||||||
__requires__ = 'ansible-awx'
|
|
||||||
import sys
|
import sys
|
||||||
from pkg_resources import load_entry_point
|
from pkg_resources import load_entry_point
|
||||||
|
__requires__ = 'awx'
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
sys.exit(
|
sys.exit(
|
||||||
load_entry_point('ansible-awx', 'console_scripts', 'awx-manage')()
|
load_entry_point('awx', 'console_scripts', 'awx-manage')()
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
Metadata-Version: 1.1
|
Metadata-Version: 1.1
|
||||||
Name: ansible-awx
|
Name: awx
|
||||||
Version: placeholder
|
Version: placeholder
|
||||||
Summary: ansible-awx: API, UI and Task Engine for Ansible
|
Summary: awx: API, UI and Task Engine for Ansible
|
||||||
Home-page: http://github.com/ansible/ansible-awx
|
Home-page: http://github.com/ansible/awx
|
||||||
Author: Ansible, Inc.
|
Author: Ansible, Inc.
|
||||||
Author-email: info@ansible.com
|
Author-email: info@ansible.com
|
||||||
License: Proprietary
|
License: Proprietary
|
||||||
Description: Ansible AWXprovides a web-based user interface, REST API and task engine built on top of Ansible
|
Description: AWX provides a web-based user interface, REST API and task engine built on top of Ansible
|
||||||
Keywords: ansible
|
Keywords: ansible
|
||||||
Platform: UNKNOWN
|
Platform: UNKNOWN
|
||||||
Classifier: Development Status :: 5 - Production/Stable
|
Classifier: Development Status :: 5 - Production/Stable
|
||||||
@@ -21,9 +21,9 @@ else
|
|||||||
echo "Failed to find awx source tree, map your development tree volume"
|
echo "Failed to find awx source tree, map your development tree volume"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
cp -R /tmp/ansible_awx.egg-info /awx_devel/ || true
|
cp -R /tmp/awx.egg-info /awx_devel/ || true
|
||||||
sed -i "s/placeholder/$(git describe --long | sed 's/\./\\./g')/" /awx_devel/ansible_awx.egg-info/PKG-INFO
|
sed -i "s/placeholder/$(git describe --long | sed 's/\./\\./g')/" /awx_devel/awx.egg-info/PKG-INFO
|
||||||
cp /tmp/ansible-awx.egg-link /venv/awx/lib/python2.7/site-packages/ansible-awx.egg-link
|
cp /tmp/awx.egg-link /venv/awx/lib/python2.7/site-packages/awx.egg-link
|
||||||
ln -s /awx_devel/tools/rdb.py /venv/awx/lib/python2.7/site-packages/rdb.py || true
|
ln -s /awx_devel/tools/rdb.py /venv/awx/lib/python2.7/site-packages/rdb.py || true
|
||||||
yes | cp -rf /awx_devel/tools/docker-compose/supervisor.conf /supervisor.conf
|
yes | cp -rf /awx_devel/tools/docker-compose/supervisor.conf /supervisor.conf
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
. /venv/awx/bin/activate
|
. /venv/awx/bin/activate
|
||||||
exec env TOWER_LIB_DIRECTORY=/awx_lib /awx_devel/run.py "$@"
|
exec env AWX_LIB_DIRECTORY=/awx_lib /awx_devel/run.py "$@"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
AWX_LIB=`/var/lib/awx/venv/awx/bin/python -c 'import os, awx; print os.path.dirname(awx.__file__)'`
|
AWX_LIB=`/var/lib/awx/venv/awx/bin/python -c 'import os, awx; print os.path.dirname(awx.__file__)'`
|
||||||
. /var/lib/awx/venv/awx/bin/activate
|
. /var/lib/awx/venv/awx/bin/activate
|
||||||
exec env TOWER_LIB_DIRECTORY=$AWX_LIB/lib /var/lib/awx/venv/awx/bin/python $AWX_LIB/main/isolated/run.pyc "$@"
|
exec env AWX_LIB_DIRECTORY=$AWX_LIB/lib /var/lib/awx/venv/awx/bin/python $AWX_LIB/main/isolated/run.pyc "$@"
|
||||||
|
|||||||
Reference in New Issue
Block a user