mirror of
https://github.com/ansible/awx.git
synced 2026-01-16 20:30:46 -03:30
Merge branch 'release_2.4.0' into devel
* release_2.4.0: (94 commits) Fix up location of apt key for mongo Handle playbook_on_include events from v2 ansible if basic auth in headers, don't use cookie token Add a docker-ui container to the compose workflow Fix custom inventory scripts on org deletion adding check for missing session time from local storage Properly handle idle/expired session across tabs fixed system tracking date issues Improve postgres user creation Remove silly user check in postgres config Fix typo in `clean` target fixed sources scope regions issue fixed scan date being the earlier one when identical fixed the console errors for the sources scope fixed console error fixed standard out load for adhoc commands fixing custom inventory script error Revert "change list separator for adhoc host patterns" Revert "update awFeature ldap to enterprise_auth" Revert "Change delimiter from ':' to ','." ...
This commit is contained in:
commit
45982e50e6
12
Makefile
12
Makefile
@ -201,7 +201,7 @@ clean-bundle:
|
||||
# Remove temporary build files, compiled Python files.
|
||||
clean: clean-rpm clean-deb clean-grunt clean-ui clean-tar clean-packer clean-bundle
|
||||
rm -rf awx/lib/site-packages
|
||||
rm- rf awx/lib/.deps_built
|
||||
rm -rf awx/lib/.deps_built
|
||||
rm -rf dist/*
|
||||
rm -rf tmp
|
||||
mkdir tmp
|
||||
@ -700,5 +700,13 @@ docker-compose:
|
||||
docker-compose -f tools/docker-compose.yml up --no-recreate
|
||||
|
||||
docker-compose-test:
|
||||
cd tools && docker-compose run --service-ports tower /bin/bash
|
||||
cd tools && docker-compose run --rm --service-ports tower /bin/bash
|
||||
|
||||
mongo-debug-ui:
|
||||
docker run -it --rm --name mongo-express --link tools_mongo_1:mongo -e ME_CONFIG_OPTIONS_EDITORTHEME=ambiance -e ME_CONFIG_BASICAUTH_USERNAME=admin -e ME_CONFIG_BASICAUTH_PASSWORD=password -p 8081:8081 knickers/mongo-express
|
||||
|
||||
mongo-container:
|
||||
docker run -it --link tools_mongo_1:mongo --rm mongo sh -c 'exec mongo "$MONGO_PORT_27017_TCP_ADDR:$MONGO_PORT_27017_TCP_PORT/system_tracking_dev"'
|
||||
|
||||
psql-container:
|
||||
docker run -it --link tools_postgres_1:postgres --rm postgres:9.4.1 sh -c 'exec psql -h "$$POSTGRES_PORT_5432_TCP_ADDR" -p "$$POSTGRES_PORT_5432_TCP_PORT" -U postgres'
|
||||
|
||||
@ -50,7 +50,10 @@ class TokenAuthentication(authentication.TokenAuthentication):
|
||||
auth = TokenAuthentication._get_x_auth_token_header(request).split()
|
||||
if not auth or auth[0].lower() != 'token':
|
||||
auth = authentication.get_authorization_header(request).split()
|
||||
if not auth or auth[0].lower() != 'token':
|
||||
# Prefer basic auth over cookie token
|
||||
if auth and auth[0].lower() == 'basic':
|
||||
return None
|
||||
elif not auth or auth[0].lower() != 'token':
|
||||
auth = TokenAuthentication._get_auth_token_cookie(request).split()
|
||||
if not auth or auth[0].lower() != 'token':
|
||||
return None
|
||||
|
||||
@ -31,4 +31,17 @@ def feature_enabled(name):
|
||||
return False
|
||||
|
||||
# Return the correct feature flag.
|
||||
return get_license()['features'].get(name, False)
|
||||
return license['features'].get(name, False)
|
||||
|
||||
def feature_exists(name):
|
||||
"""Return True if the requested feature is enabled, False otherwise.
|
||||
If the feature does not exist, raise KeyError.
|
||||
"""
|
||||
license = get_license()
|
||||
|
||||
# Sanity check: If there is no license, the feature is considered
|
||||
# to be off.
|
||||
if 'features' not in license:
|
||||
return False
|
||||
|
||||
return name in license['features']
|
||||
|
||||
@ -60,7 +60,7 @@ from awx.api.utils.decorators import paginated
|
||||
from awx.api.filters import MongoFilterBackend
|
||||
from awx.api.generics import get_view_name
|
||||
from awx.api.generics import * # noqa
|
||||
from awx.api.license import feature_enabled, LicenseForbids
|
||||
from awx.api.license import feature_enabled, feature_exists, LicenseForbids
|
||||
from awx.main.models import * # noqa
|
||||
from awx.main.utils import * # noqa
|
||||
from awx.api.permissions import * # noqa
|
||||
@ -527,6 +527,11 @@ class AuthView(APIView):
|
||||
data = SortedDict()
|
||||
err_backend, err_message = request.session.get('social_auth_error', (None, None))
|
||||
for name, backend in load_backends(settings.AUTHENTICATION_BACKENDS).items():
|
||||
if (not feature_exists('enterprise_auth') and
|
||||
not feature_enabled('ldap')) or \
|
||||
(not feature_enabled('enterprise_auth') and
|
||||
name in ['saml', 'radius']):
|
||||
continue
|
||||
login_url = reverse('social:begin', args=(name,))
|
||||
complete_url = request.build_absolute_uri(reverse('social:complete', args=(name,)))
|
||||
backend_data = {
|
||||
|
||||
@ -262,6 +262,7 @@ class OrganizationAccess(BaseAccess):
|
||||
self.user in obj.admins.all())
|
||||
|
||||
def can_delete(self, obj):
|
||||
self.check_license(feature='multiple_organizations')
|
||||
return self.can_change(obj, None)
|
||||
|
||||
class InventoryAccess(BaseAccess):
|
||||
@ -672,22 +673,22 @@ class ProjectAccess(BaseAccess):
|
||||
- I am on a team associated with the project.
|
||||
- I have been explicitly granted permission to run/check jobs using the
|
||||
project.
|
||||
- I created it (for now?).
|
||||
- I created the project but it isn't associated with an organization
|
||||
I can change/delete when:
|
||||
- I am a superuser.
|
||||
- I am an admin in an organization associated with the project.
|
||||
- I created it (for now?).
|
||||
- I created the project but it isn't associated with an organization
|
||||
'''
|
||||
|
||||
model = Project
|
||||
|
||||
def get_queryset(self):
|
||||
qs = Project.objects.filter(active=True).distinct()
|
||||
qs = qs.select_related('created_by', 'modified_by', 'credential', 'current_update', 'last_update')
|
||||
qs = qs.select_related('modified_by', 'credential', 'current_update', 'last_update')
|
||||
if self.user.is_superuser:
|
||||
return qs
|
||||
team_ids = set(Team.objects.filter(users__in=[self.user]).values_list('id', flat=True))
|
||||
qs = qs.filter(Q(created_by=self.user) |
|
||||
qs = qs.filter(Q(created_by=self.user, organizations__isnull=True) |
|
||||
Q(organizations__admins__in=[self.user], organizations__active=True) |
|
||||
Q(organizations__users__in=[self.user], organizations__active=True) |
|
||||
Q(teams__in=team_ids))
|
||||
@ -719,7 +720,7 @@ class ProjectAccess(BaseAccess):
|
||||
def can_change(self, obj, data):
|
||||
if self.user.is_superuser:
|
||||
return True
|
||||
if obj.created_by == self.user:
|
||||
if obj.created_by == self.user and not obj.organizations.filter(active=True).count():
|
||||
return True
|
||||
if obj.organizations.filter(active=True, admins__in=[self.user]).exists():
|
||||
return True
|
||||
@ -1605,7 +1606,7 @@ class CustomInventoryScriptAccess(BaseAccess):
|
||||
model = CustomInventoryScript
|
||||
|
||||
def get_queryset(self):
|
||||
qs = self.model.objects.filter(active=True, organization__active=True).distinct()
|
||||
qs = self.model.objects.filter(active=True).distinct()
|
||||
if not self.user.is_superuser:
|
||||
qs = qs.filter(Q(organization__admins__in=[self.user]) | Q(organization__users__in=[self.user]))
|
||||
return qs
|
||||
|
||||
34
awx/main/management/commands/cleanup_authtokens.py
Normal file
34
awx/main/management/commands/cleanup_authtokens.py
Normal file
@ -0,0 +1,34 @@
|
||||
# Copyright (c) 2015 Ansible, Inc.
|
||||
# All Rights Reserved.
|
||||
|
||||
# Python
|
||||
import logging
|
||||
|
||||
# Django
|
||||
from django.db import transaction
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.utils.timezone import now
|
||||
|
||||
# AWX
|
||||
from awx.main.models import * # noqa
|
||||
|
||||
class Command(BaseCommand):
|
||||
'''
|
||||
Management command to cleanup expired auth tokens
|
||||
'''
|
||||
|
||||
help = 'Cleanup expired auth tokens.'
|
||||
|
||||
def init_logging(self):
|
||||
self.logger = logging.getLogger('awx.main.commands.cleanup_authtokens')
|
||||
handler = logging.StreamHandler()
|
||||
handler.setFormatter(logging.Formatter('%(message)s'))
|
||||
self.logger.addHandler(handler)
|
||||
self.logger.propagate = False
|
||||
|
||||
@transaction.atomic
|
||||
def handle(self, *args, **options):
|
||||
self.init_logging()
|
||||
tokens_removed = AuthToken.objects.filter(expires__lt=now())
|
||||
self.logger.log(99, "Removing %d expired auth tokens" % tokens_removed.count())
|
||||
tokens_removed.delete()
|
||||
@ -118,3 +118,10 @@ class Command(BaseCommand):
|
||||
self.logger.log(99, "Removed %d items", n_deleted_items)
|
||||
else:
|
||||
self.logger.log(99, "Would have removed %d items", n_deleted_items)
|
||||
|
||||
tokens_removed = AuthToken.objects.filter(expires__lt=now())
|
||||
if not self.dry_run:
|
||||
self.logger.log(99, "Removed %d expired auth tokens" % tokens_removed.count())
|
||||
tokens_removed.delete()
|
||||
else:
|
||||
self.logger.log(99, "Would have removed %d expired auth tokens" % tokens_removed.count())
|
||||
|
||||
@ -883,14 +883,14 @@ class Command(NoArgsCommand):
|
||||
all_obj = self.inventory
|
||||
all_name = 'inventory'
|
||||
db_variables = all_obj.variables_dict
|
||||
if self.overwrite_vars or self.overwrite:
|
||||
if self.overwrite_vars:
|
||||
db_variables = self.all_group.variables
|
||||
else:
|
||||
db_variables.update(self.all_group.variables)
|
||||
if db_variables != all_obj.variables_dict:
|
||||
all_obj.variables = json.dumps(db_variables)
|
||||
all_obj.save(update_fields=['variables'])
|
||||
if self.overwrite_vars or self.overwrite:
|
||||
if self.overwrite_vars:
|
||||
self.logger.info('%s variables replaced from "all" group', all_name.capitalize())
|
||||
else:
|
||||
self.logger.info('%s variables updated from "all" group', all_name.capitalize())
|
||||
@ -920,14 +920,14 @@ class Command(NoArgsCommand):
|
||||
for group in self.inventory.groups.filter(name__in=group_names):
|
||||
mem_group = self.all_group.all_groups[group.name]
|
||||
db_variables = group.variables_dict
|
||||
if self.overwrite_vars or self.overwrite:
|
||||
if self.overwrite_vars:
|
||||
db_variables = mem_group.variables
|
||||
else:
|
||||
db_variables.update(mem_group.variables)
|
||||
if db_variables != group.variables_dict:
|
||||
group.variables = json.dumps(db_variables)
|
||||
group.save(update_fields=['variables'])
|
||||
if self.overwrite_vars or self.overwrite:
|
||||
if self.overwrite_vars:
|
||||
self.logger.info('Group "%s" variables replaced', group.name)
|
||||
else:
|
||||
self.logger.info('Group "%s" variables updated', group.name)
|
||||
@ -959,7 +959,7 @@ class Command(NoArgsCommand):
|
||||
def _update_db_host_from_mem_host(self, db_host, mem_host):
|
||||
# Update host variables.
|
||||
db_variables = db_host.variables_dict
|
||||
if self.overwrite_vars or self.overwrite:
|
||||
if self.overwrite_vars:
|
||||
db_variables = mem_host.variables
|
||||
else:
|
||||
db_variables.update(mem_host.variables)
|
||||
@ -994,7 +994,7 @@ class Command(NoArgsCommand):
|
||||
else:
|
||||
self.logger.info('Host "%s" instance_id added', mem_host.name)
|
||||
if 'variables' in update_fields:
|
||||
if self.overwrite_vars or self.overwrite:
|
||||
if self.overwrite_vars:
|
||||
self.logger.info('Host "%s" variables replaced', mem_host.name)
|
||||
else:
|
||||
self.logger.info('Host "%s" variables updated', mem_host.name)
|
||||
|
||||
@ -130,6 +130,7 @@ class CallbackReceiver(object):
|
||||
'playbook_on_task_start',
|
||||
'playbook_on_no_hosts_matched',
|
||||
'playbook_on_no_hosts_remaining',
|
||||
'playbook_on_include',
|
||||
'playbook_on_import_for_host',
|
||||
'playbook_on_not_import_for_host'):
|
||||
parent = job_parent_events.get('playbook_on_play_start', None)
|
||||
|
||||
519
awx/main/migrations/0074_v240_changes.py
Normal file
519
awx/main/migrations/0074_v240_changes.py
Normal file
@ -0,0 +1,519 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from south.utils import datetime_utils as datetime
|
||||
from south.db import db
|
||||
from south.v2 import SchemaMigration
|
||||
from django.db import models
|
||||
|
||||
|
||||
class Migration(SchemaMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
# Changing field 'CustomInventoryScript.organization'
|
||||
db.alter_column(u'main_custominventoryscript', 'organization_id', self.gf('django.db.models.fields.related.ForeignKey')(null=True, on_delete=models.SET_NULL, to=orm['main.Organization']))
|
||||
|
||||
def backwards(self, orm):
|
||||
# Changing field 'CustomInventoryScript.organization'
|
||||
db.alter_column(u'main_custominventoryscript', 'organization_id', self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['main.Organization']))
|
||||
|
||||
models = {
|
||||
u'auth.group': {
|
||||
'Meta': {'object_name': 'Group'},
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
u'auth.permission': {
|
||||
'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
|
||||
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||
},
|
||||
u'auth.user': {
|
||||
'Meta': {'object_name': 'User'},
|
||||
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Group']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "u'user_set'", 'blank': 'True', 'to': u"orm['auth.Permission']"}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||
},
|
||||
u'contenttypes.contenttype': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||
},
|
||||
'main.activitystream': {
|
||||
'Meta': {'object_name': 'ActivityStream'},
|
||||
'actor': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'activity_stream'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'ad_hoc_command': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.AdHocCommand']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'changes': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'credential': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Credential']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'custom_inventory_script': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.CustomInventoryScript']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'group': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'host': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Host']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'inventory': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Inventory']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'inventory_source': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.InventorySource']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'inventory_update': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.InventoryUpdate']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'job': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Job']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'job_template': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.JobTemplate']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'object1': ('django.db.models.fields.TextField', [], {}),
|
||||
'object2': ('django.db.models.fields.TextField', [], {}),
|
||||
'object_relationship_type': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'operation': ('django.db.models.fields.CharField', [], {'max_length': '13'}),
|
||||
'organization': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Organization']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'permission': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'project': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Project']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'project_update': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.ProjectUpdate']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'schedule': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Schedule']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'team': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Team']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||
'timestamp': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'unified_job': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'activity_stream_as_unified_job+'", 'blank': 'True', 'to': "orm['main.UnifiedJob']"}),
|
||||
'unified_job_template': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'activity_stream_as_unified_job_template+'", 'blank': 'True', 'to': "orm['main.UnifiedJobTemplate']"}),
|
||||
'user': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.User']", 'symmetrical': 'False', 'blank': 'True'})
|
||||
},
|
||||
'main.adhoccommand': {
|
||||
'Meta': {'object_name': 'AdHocCommand', '_ormbases': ['main.UnifiedJob']},
|
||||
'become_enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'credential': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'ad_hoc_commands'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Credential']"}),
|
||||
'forks': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'blank': 'True'}),
|
||||
'hosts': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'ad_hoc_commands'", 'symmetrical': 'False', 'through': "orm['main.AdHocCommandEvent']", 'to': "orm['main.Host']"}),
|
||||
'inventory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ad_hoc_commands'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Inventory']"}),
|
||||
'job_type': ('django.db.models.fields.CharField', [], {'default': "'run'", 'max_length': '64'}),
|
||||
'limit': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'module_args': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'module_name': ('django.db.models.fields.CharField', [], {'default': "'command'", 'max_length': '1024', 'blank': 'True'}),
|
||||
u'unifiedjob_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['main.UnifiedJob']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'verbosity': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'blank': 'True'})
|
||||
},
|
||||
'main.adhoccommandevent': {
|
||||
'Meta': {'ordering': "('-pk',)", 'unique_together': "[('ad_hoc_command', 'host_name')]", 'object_name': 'AdHocCommandEvent'},
|
||||
'ad_hoc_command': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'ad_hoc_command_events'", 'to': "orm['main.AdHocCommand']"}),
|
||||
'changed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'counter': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'event': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'event_data': ('jsonfield.fields.JSONField', [], {'default': '{}', 'blank': 'True'}),
|
||||
'failed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'host': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'ad_hoc_command_events'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Host']"}),
|
||||
'host_name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'})
|
||||
},
|
||||
'main.authtoken': {
|
||||
'Meta': {'object_name': 'AuthToken'},
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'expires': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||
'key': ('django.db.models.fields.CharField', [], {'max_length': '40', 'primary_key': 'True'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'reason': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'request_hash': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '40', 'blank': 'True'}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'auth_tokens'", 'to': u"orm['auth.User']"})
|
||||
},
|
||||
'main.credential': {
|
||||
'Meta': {'ordering': "('kind', 'name')", 'unique_together': "[('user', 'team', 'kind', 'name')]", 'object_name': 'Credential'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'become_method': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '32', 'blank': 'True'}),
|
||||
'become_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'become_username': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'cloud': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'credential\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'host': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'kind': ('django.db.models.fields.CharField', [], {'default': "'ssh'", 'max_length': '32'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'credential\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
|
||||
'password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'project': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100', 'blank': 'True'}),
|
||||
'security_token': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'ssh_key_data': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'ssh_key_unlock': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'team': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'credentials'", 'null': 'True', 'blank': 'True', 'to': "orm['main.Team']"}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'credentials'", 'null': 'True', 'blank': 'True', 'to': u"orm['auth.User']"}),
|
||||
'username': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'vault_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'})
|
||||
},
|
||||
'main.custominventoryscript': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "[('name', 'organization')]", 'object_name': 'CustomInventoryScript'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'custominventoryscript\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'custominventoryscript\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
|
||||
'organization': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'custom_inventory_scripts'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Organization']"}),
|
||||
'script': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'})
|
||||
},
|
||||
'main.group': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "(('name', 'inventory'),)", 'object_name': 'Group'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'group\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'groups_with_active_failures': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'has_active_failures': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'has_inventory_sources': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'hosts': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'groups'", 'blank': 'True', 'to': "orm['main.Host']"}),
|
||||
'hosts_with_active_failures': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'inventory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'groups'", 'to': "orm['main.Inventory']"}),
|
||||
'inventory_sources': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'groups'", 'symmetrical': 'False', 'to': "orm['main.InventorySource']"}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'group\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
|
||||
'parents': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'children'", 'blank': 'True', 'to': "orm['main.Group']"}),
|
||||
'total_groups': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'total_hosts': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'variables': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'})
|
||||
},
|
||||
'main.host': {
|
||||
'Meta': {'ordering': "('inventory', 'name')", 'unique_together': "(('name', 'inventory'),)", 'object_name': 'Host'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'host\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'has_active_failures': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'has_inventory_sources': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'instance_id': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100', 'blank': 'True'}),
|
||||
'inventory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'hosts'", 'to': "orm['main.Inventory']"}),
|
||||
'inventory_sources': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'hosts'", 'symmetrical': 'False', 'to': "orm['main.InventorySource']"}),
|
||||
'last_job': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'hosts_as_last_job+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Job']"}),
|
||||
'last_job_host_summary': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'hosts_as_last_job_summary+'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.JobHostSummary']", 'blank': 'True', 'null': 'True'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'host\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
|
||||
'variables': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'})
|
||||
},
|
||||
'main.instance': {
|
||||
'Meta': {'object_name': 'Instance'},
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
'hostname': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '250'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'primary': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'uuid': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40'})
|
||||
},
|
||||
'main.inventory': {
|
||||
'Meta': {'ordering': "('name',)", 'unique_together': "[('name', 'organization')]", 'object_name': 'Inventory'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'inventory\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'groups_with_active_failures': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'has_active_failures': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'has_inventory_sources': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'hosts_with_active_failures': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'inventory_sources_with_failures': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'inventory\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '512'}),
|
||||
'organization': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'inventories'", 'to': "orm['main.Organization']"}),
|
||||
'total_groups': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'total_hosts': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'total_inventory_sources': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'variables': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'})
|
||||
},
|
||||
'main.inventorysource': {
|
||||
'Meta': {'object_name': 'InventorySource', '_ormbases': ['main.UnifiedJobTemplate']},
|
||||
'credential': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'inventorysources'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Credential']", 'blank': 'True', 'null': 'True'}),
|
||||
'group': ('awx.main.fields.AutoOneToOneField', [], {'default': 'None', 'related_name': "'inventory_source'", 'unique': 'True', 'null': 'True', 'to': "orm['main.Group']"}),
|
||||
'group_by': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'instance_filters': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'inventory': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'inventory_sources'", 'null': 'True', 'to': "orm['main.Inventory']"}),
|
||||
'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'overwrite_vars': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'source': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '32', 'blank': 'True'}),
|
||||
'source_path': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'source_regions': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'source_script': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['main.CustomInventoryScript']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}),
|
||||
'source_vars': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
u'unifiedjobtemplate_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['main.UnifiedJobTemplate']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'update_cache_timeout': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'update_on_launch': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
|
||||
},
|
||||
'main.inventoryupdate': {
|
||||
'Meta': {'object_name': 'InventoryUpdate', '_ormbases': ['main.UnifiedJob']},
|
||||
'credential': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'inventoryupdates'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Credential']", 'blank': 'True', 'null': 'True'}),
|
||||
'group_by': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'instance_filters': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'inventory_source': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'inventory_updates'", 'to': "orm['main.InventorySource']"}),
|
||||
'license_error': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'overwrite': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'overwrite_vars': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'source': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '32', 'blank': 'True'}),
|
||||
'source_path': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'source_regions': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'source_script': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['main.CustomInventoryScript']", 'null': 'True', 'on_delete': 'models.SET_NULL', 'blank': 'True'}),
|
||||
'source_vars': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
u'unifiedjob_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['main.UnifiedJob']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
'main.job': {
|
||||
'Meta': {'ordering': "('id',)", 'object_name': 'Job', '_ormbases': ['main.UnifiedJob']},
|
||||
'become_enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'cloud_credential': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobs_as_cloud_credential+'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Credential']", 'blank': 'True', 'null': 'True'}),
|
||||
'credential': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobs'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Credential']", 'blank': 'True', 'null': 'True'}),
|
||||
'extra_vars': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'force_handlers': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'forks': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'blank': 'True'}),
|
||||
'hosts': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'jobs'", 'symmetrical': 'False', 'through': "orm['main.JobHostSummary']", 'to': "orm['main.Host']"}),
|
||||
'inventory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobs'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Inventory']"}),
|
||||
'job_tags': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'job_template': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobs'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.JobTemplate']", 'blank': 'True', 'null': 'True'}),
|
||||
'job_type': ('django.db.models.fields.CharField', [], {'default': "'run'", 'max_length': '64'}),
|
||||
'limit': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'playbook': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobs'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Project']", 'blank': 'True', 'null': 'True'}),
|
||||
'skip_tags': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'start_at_task': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
u'unifiedjob_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['main.UnifiedJob']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'verbosity': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'blank': 'True'})
|
||||
},
|
||||
'main.jobevent': {
|
||||
'Meta': {'ordering': "('pk',)", 'object_name': 'JobEvent'},
|
||||
'changed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'counter': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'event': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||
'event_data': ('jsonfield.fields.JSONField', [], {'default': '{}', 'blank': 'True'}),
|
||||
'failed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'host': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'job_events_as_primary_host'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Host']"}),
|
||||
'host_name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024'}),
|
||||
'hosts': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'job_events'", 'symmetrical': 'False', 'to': "orm['main.Host']"}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'job': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'job_events'", 'to': "orm['main.Job']"}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'parent': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'children'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.JobEvent']"}),
|
||||
'play': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024'}),
|
||||
'role': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024'}),
|
||||
'task': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024'})
|
||||
},
|
||||
'main.jobhostsummary': {
|
||||
'Meta': {'ordering': "('-pk',)", 'unique_together': "[('job', 'host_name')]", 'object_name': 'JobHostSummary'},
|
||||
'changed': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'dark': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'failed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'failures': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'host': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'job_host_summaries'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Host']"}),
|
||||
'host_name': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'job': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'job_host_summaries'", 'to': "orm['main.Job']"}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'ok': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'processed': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
|
||||
'skipped': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'})
|
||||
},
|
||||
'main.joborigin': {
|
||||
'Meta': {'object_name': 'JobOrigin'},
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'instance': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['main.Instance']"}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
|
||||
'unified_job': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'job_origin'", 'unique': 'True', 'to': "orm['main.UnifiedJob']"})
|
||||
},
|
||||
'main.jobtemplate': {
|
||||
'Meta': {'ordering': "('name',)", 'object_name': 'JobTemplate', '_ormbases': ['main.UnifiedJobTemplate']},
|
||||
'ask_variables_on_launch': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'become_enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'cloud_credential': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobtemplates_as_cloud_credential+'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Credential']", 'blank': 'True', 'null': 'True'}),
|
||||
'credential': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobtemplates'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Credential']", 'blank': 'True', 'null': 'True'}),
|
||||
'extra_vars': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'force_handlers': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'forks': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'blank': 'True'}),
|
||||
'host_config_key': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'inventory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobtemplates'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Inventory']"}),
|
||||
'job_tags': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'job_type': ('django.db.models.fields.CharField', [], {'default': "'run'", 'max_length': '64'}),
|
||||
'limit': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'playbook': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobtemplates'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Project']", 'blank': 'True', 'null': 'True'}),
|
||||
'skip_tags': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'start_at_task': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'survey_enabled': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'survey_spec': ('jsonfield.fields.JSONField', [], {'default': '{}', 'blank': 'True'}),
|
||||
u'unifiedjobtemplate_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['main.UnifiedJobTemplate']", 'unique': 'True', 'primary_key': 'True'}),
|
||||
'verbosity': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'blank': 'True'})
|
||||
},
|
||||
'main.organization': {
|
||||
'Meta': {'ordering': "('name',)", 'object_name': 'Organization'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'admins': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'admin_of_organizations'", 'blank': 'True', 'to': u"orm['auth.User']"}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'organization\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'organization\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '512'}),
|
||||
'projects': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'organizations'", 'blank': 'True', 'to': "orm['main.Project']"}),
|
||||
'users': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'organizations'", 'blank': 'True', 'to': u"orm['auth.User']"})
|
||||
},
|
||||
'main.permission': {
|
||||
'Meta': {'object_name': 'Permission'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'permission\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'inventory': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'permissions'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Inventory']"}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'permission\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
|
||||
'permission_type': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
|
||||
'project': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'permissions'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Project']"}),
|
||||
'run_ad_hoc_commands': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'team': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'permissions'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Team']"}),
|
||||
'user': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'permissions'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"})
|
||||
},
|
||||
'main.profile': {
|
||||
'Meta': {'object_name': 'Profile'},
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'ldap_dn': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'user': ('awx.main.fields.AutoOneToOneField', [], {'related_name': "'profile'", 'unique': 'True', 'to': u"orm['auth.User']"})
|
||||
},
|
||||
'main.project': {
|
||||
'Meta': {'ordering': "('id',)", 'object_name': 'Project', '_ormbases': ['main.UnifiedJobTemplate']},
|
||||
'credential': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'projects'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Credential']", 'blank': 'True', 'null': 'True'}),
|
||||
'local_path': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'blank': 'True'}),
|
||||
'scm_branch': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '256', 'blank': 'True'}),
|
||||
'scm_clean': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'scm_delete_on_next_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'scm_delete_on_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'scm_type': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '8', 'blank': 'True'}),
|
||||
'scm_update_cache_timeout': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'blank': 'True'}),
|
||||
'scm_update_on_launch': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'scm_url': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
u'unifiedjobtemplate_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['main.UnifiedJobTemplate']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
'main.projectupdate': {
|
||||
'Meta': {'object_name': 'ProjectUpdate', '_ormbases': ['main.UnifiedJob']},
|
||||
'credential': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'projectupdates'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.Credential']", 'blank': 'True', 'null': 'True'}),
|
||||
'local_path': ('django.db.models.fields.CharField', [], {'max_length': '1024', 'blank': 'True'}),
|
||||
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'project_updates'", 'to': "orm['main.Project']"}),
|
||||
'scm_branch': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '256', 'blank': 'True'}),
|
||||
'scm_clean': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'scm_delete_on_update': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'scm_type': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '8', 'blank': 'True'}),
|
||||
'scm_url': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
u'unifiedjob_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['main.UnifiedJob']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
'main.schedule': {
|
||||
'Meta': {'ordering': "['-next_run']", 'object_name': 'Schedule'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'schedule\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'dtend': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
|
||||
'dtstart': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
|
||||
'enabled': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'extra_data': ('jsonfield.fields.JSONField', [], {'default': '{}', 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'schedule\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '512'}),
|
||||
'next_run': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
|
||||
'rrule': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||
'unified_job_template': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'schedules'", 'to': "orm['main.UnifiedJobTemplate']"})
|
||||
},
|
||||
'main.systemjob': {
|
||||
'Meta': {'ordering': "('id',)", 'object_name': 'SystemJob', '_ormbases': ['main.UnifiedJob']},
|
||||
'extra_vars': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'job_type': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '32', 'blank': 'True'}),
|
||||
'system_job_template': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobs'", 'on_delete': 'models.SET_NULL', 'default': 'None', 'to': "orm['main.SystemJobTemplate']", 'blank': 'True', 'null': 'True'}),
|
||||
u'unifiedjob_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['main.UnifiedJob']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
'main.systemjobtemplate': {
|
||||
'Meta': {'object_name': 'SystemJobTemplate', '_ormbases': ['main.UnifiedJobTemplate']},
|
||||
'job_type': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '32', 'blank': 'True'}),
|
||||
u'unifiedjobtemplate_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['main.UnifiedJobTemplate']", 'unique': 'True', 'primary_key': 'True'})
|
||||
},
|
||||
'main.team': {
|
||||
'Meta': {'ordering': "('organization__name', 'name')", 'unique_together': "[('organization', 'name')]", 'object_name': 'Team'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'team\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'team\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
|
||||
'organization': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'teams'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Organization']"}),
|
||||
'projects': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'teams'", 'blank': 'True', 'to': "orm['main.Project']"}),
|
||||
'users': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'teams'", 'blank': 'True', 'to': u"orm['auth.User']"})
|
||||
},
|
||||
'main.unifiedjob': {
|
||||
'Meta': {'object_name': 'UnifiedJob'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'cancel_flag': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'celery_task_id': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '100', 'blank': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'unifiedjob\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'dependent_jobs': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'dependent_jobs_rel_+'", 'to': "orm['main.UnifiedJob']"}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'elapsed': ('django.db.models.fields.DecimalField', [], {'max_digits': '12', 'decimal_places': '3'}),
|
||||
'failed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'finished': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'job_args': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'job_cwd': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'job_env': ('jsonfield.fields.JSONField', [], {'default': '{}', 'blank': 'True'}),
|
||||
'job_explanation': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'launch_type': ('django.db.models.fields.CharField', [], {'default': "'manual'", 'max_length': '20'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'unifiedjob\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
|
||||
'old_pk': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'null': 'True'}),
|
||||
'polymorphic_ctype': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'polymorphic_main.unifiedjob_set'", 'null': 'True', 'to': u"orm['contenttypes.ContentType']"}),
|
||||
'result_stdout_file': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'result_stdout_text': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'result_traceback': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'schedule': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['main.Schedule']", 'null': 'True', 'on_delete': 'models.SET_NULL'}),
|
||||
'start_args': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'started': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'default': "'new'", 'max_length': '20'}),
|
||||
'unified_job_template': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'unifiedjob_unified_jobs'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.UnifiedJobTemplate']"})
|
||||
},
|
||||
'main.unifiedjobtemplate': {
|
||||
'Meta': {'unique_together': "[('polymorphic_ctype', 'name')]", 'object_name': 'UnifiedJobTemplate'},
|
||||
'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||
'created': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'created_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'unifiedjobtemplate\', \'app_label\': \'main\'}(class)s_created+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'current_job': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'unifiedjobtemplate_as_current_job+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.UnifiedJob']"}),
|
||||
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}),
|
||||
'has_schedules': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'last_job': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'unifiedjobtemplate_as_last_job+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.UnifiedJob']"}),
|
||||
'last_job_failed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||
'last_job_run': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
|
||||
'modified': ('django.db.models.fields.DateTimeField', [], {'default': 'None'}),
|
||||
'modified_by': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': '"{\'class\': \'unifiedjobtemplate\', \'app_label\': \'main\'}(class)s_modified+"', 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': u"orm['auth.User']"}),
|
||||
'name': ('django.db.models.fields.CharField', [], {'max_length': '512'}),
|
||||
'next_job_run': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True'}),
|
||||
'next_schedule': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'unifiedjobtemplate_as_next_schedule+'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Schedule']"}),
|
||||
'old_pk': ('django.db.models.fields.PositiveIntegerField', [], {'default': 'None', 'null': 'True'}),
|
||||
'polymorphic_ctype': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'polymorphic_main.unifiedjobtemplate_set'", 'null': 'True', 'to': u"orm['contenttypes.ContentType']"}),
|
||||
'status': ('django.db.models.fields.CharField', [], {'default': "'ok'", 'max_length': '32'})
|
||||
}
|
||||
}
|
||||
|
||||
complete_apps = ['main']
|
||||
@ -1281,7 +1281,9 @@ class CustomInventoryScript(CommonModelNameNotUnique):
|
||||
'Organization',
|
||||
related_name='custom_inventory_scripts',
|
||||
help_text=_('Organization owning this inventory script'),
|
||||
on_delete=models.CASCADE,
|
||||
blank=False,
|
||||
null=True,
|
||||
on_delete=models.SET_NULL,
|
||||
)
|
||||
|
||||
def get_absolute_url(self):
|
||||
|
||||
@ -53,6 +53,12 @@ class Organization(CommonModel):
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
def mark_inactive(self, save=True):
|
||||
for script in self.custom_inventory_scripts.all():
|
||||
script.organization = None
|
||||
script.save()
|
||||
super(Organization, self).mark_inactive(save=save)
|
||||
|
||||
|
||||
class Team(CommonModelNameNotUnique):
|
||||
'''
|
||||
|
||||
@ -162,6 +162,7 @@ def handle_work_error(self, task_id, subtasks=None):
|
||||
print('Executing error task id %s, subtasks: %s' %
|
||||
(str(self.request.id), str(subtasks)))
|
||||
first_task = None
|
||||
first_task_id = None
|
||||
first_task_type = ''
|
||||
first_task_name = ''
|
||||
if subtasks is not None:
|
||||
@ -184,13 +185,14 @@ def handle_work_error(self, task_id, subtasks=None):
|
||||
break
|
||||
if first_task is None:
|
||||
first_task = instance
|
||||
first_task_id = instance.id
|
||||
first_task_type = each_task['type']
|
||||
first_task_name = instance_name
|
||||
if instance.celery_task_id != task_id:
|
||||
instance.status = 'failed'
|
||||
instance.failed = True
|
||||
instance.job_explanation = "Previous Task Failed: %s for %s with celery task id: %s" % \
|
||||
(first_task_type, first_task_name, task_id)
|
||||
instance.job_explanation = 'Previous Task Failed: {"task_type": "%s", "task_name": "%s", "task_id": "%s"}' % \
|
||||
(first_task_type, first_task_name, first_task_id)
|
||||
instance.save()
|
||||
instance.socketio_emit_status("failed")
|
||||
|
||||
@ -636,12 +638,17 @@ class RunJob(BaseTask):
|
||||
Build environment dictionary for ansible-playbook.
|
||||
'''
|
||||
plugin_dir = self.get_path_to('..', 'plugins', 'callback')
|
||||
plugin_dirs = [plugin_dir]
|
||||
if hasattr(settings, 'AWX_ANSIBLE_CALLBACK_PLUGINS') and \
|
||||
settings.AWX_ANSIBLE_CALLBACK_PLUGINS:
|
||||
plugin_dirs.append(settings.AWX_ANSIBLE_CALLBACK_PLUGINS)
|
||||
plugin_path = ':'.join(plugin_dirs)
|
||||
env = super(RunJob, self).build_env(job, **kwargs)
|
||||
# Set environment variables needed for inventory and job event
|
||||
# callbacks to work.
|
||||
env['JOB_ID'] = str(job.pk)
|
||||
env['INVENTORY_ID'] = str(job.inventory.pk)
|
||||
env['ANSIBLE_CALLBACK_PLUGINS'] = plugin_dir
|
||||
env['ANSIBLE_CALLBACK_PLUGINS'] = plugin_path
|
||||
env['REST_API_URL'] = settings.INTERNAL_API_URL
|
||||
env['REST_API_TOKEN'] = job.task_auth_token or ''
|
||||
env['CALLBACK_CONSUMER_PORT'] = str(settings.CALLBACK_CONSUMER_PORT)
|
||||
|
||||
@ -192,6 +192,20 @@ class BaseTestMixin(QueueTestMixin, MockCommonlySlowTestMixin):
|
||||
self._temp_paths.append(license_path)
|
||||
os.environ['AWX_LICENSE_FILE'] = license_path
|
||||
|
||||
def create_basic_license_file(self, instance_count=100, license_date=int(time.time() + 3600)):
|
||||
writer = LicenseWriter(
|
||||
company_name='AWX',
|
||||
contact_name='AWX Admin',
|
||||
contact_email='awx@example.com',
|
||||
license_date=license_date,
|
||||
instance_count=instance_count,
|
||||
license_type='basic')
|
||||
handle, license_path = tempfile.mkstemp(suffix='.json')
|
||||
os.close(handle)
|
||||
writer.write_file(license_path)
|
||||
self._temp_paths.append(license_path)
|
||||
os.environ['AWX_LICENSE_FILE'] = license_path
|
||||
|
||||
def create_expired_license_file(self, instance_count=1000, grace_period=False):
|
||||
license_date = time.time() - 1
|
||||
if not grace_period:
|
||||
|
||||
@ -828,7 +828,7 @@ class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest):
|
||||
host_names = set(new_inv.hosts.filter(active=True).values_list('name', flat=True))
|
||||
self.assertEqual(expected_host_names, host_names)
|
||||
expected_inv_vars = {'vara': 'A', 'varc': 'C'}
|
||||
if overwrite or overwrite_vars:
|
||||
if overwrite_vars:
|
||||
expected_inv_vars.pop('varc')
|
||||
self.assertEqual(new_inv.variables_dict, expected_inv_vars)
|
||||
for host in new_inv.hosts.filter(active=True):
|
||||
@ -846,7 +846,7 @@ class InventoryImportTest(BaseCommandMixin, BaseLiveServerTest):
|
||||
for group in new_inv.groups.filter(active=True):
|
||||
if group.name == 'servers':
|
||||
expected_vars = {'varb': 'B', 'vard': 'D'}
|
||||
if overwrite or overwrite_vars:
|
||||
if overwrite_vars:
|
||||
expected_vars.pop('vard')
|
||||
self.assertEqual(group.variables_dict, expected_vars)
|
||||
children = set(group.children.filter(active=True).values_list('name', flat=True))
|
||||
|
||||
@ -267,6 +267,11 @@ class OrganizationsTest(BaseTest):
|
||||
# look at what we got back from the post, make sure we added an org
|
||||
last_org = Organization.objects.order_by('-pk')[0]
|
||||
self.assertTrue(data1['url'].endswith("/%d/" % last_org.pk))
|
||||
|
||||
# Test that not even super users can create an organization with a basic license
|
||||
self.create_basic_license_file()
|
||||
cant_org = dict(name='silly user org', description='4815162342')
|
||||
self.post(self.collection(), cant_org, expect=402, auth=self.get_super_credentials())
|
||||
|
||||
def test_post_item_subobjects_projects(self):
|
||||
|
||||
@ -437,6 +442,10 @@ class OrganizationsTest(BaseTest):
|
||||
# also check that DELETE on the collection doesn't work
|
||||
self.delete(self.collection(), expect=405, auth=self.get_super_credentials())
|
||||
|
||||
# Test that not even super users can delete an organization with a basic license
|
||||
self.create_basic_license_file()
|
||||
self.delete(urls[2], expect=402, auth=self.get_super_credentials())
|
||||
|
||||
def test_invalid_post_data(self):
|
||||
url = reverse('api:organization_list')
|
||||
# API should gracefully handle data of an invalid type.
|
||||
|
||||
@ -209,7 +209,7 @@ class ProjectsTest(BaseTransactionTest):
|
||||
self.assertEquals(results['count'], 10)
|
||||
# org admin
|
||||
results = self.get(projects, expect=200, auth=self.get_normal_credentials())
|
||||
self.assertEquals(results['count'], 10)
|
||||
self.assertEquals(results['count'], 9)
|
||||
# user on a team
|
||||
results = self.get(projects, expect=200, auth=self.get_other_credentials())
|
||||
self.assertEquals(results['count'], 5)
|
||||
@ -300,6 +300,17 @@ class ProjectsTest(BaseTransactionTest):
|
||||
got = self.get(proj_orgs, expect=200, auth=self.get_super_credentials())
|
||||
self.assertEquals(got['count'], 2)
|
||||
|
||||
# Verify that creatorship doesn't imply access if access is removed
|
||||
a_new_proj = self.make_project(created_by=self.other_django_user, playbook_content=TEST_PLAYBOOK)
|
||||
self.organizations[0].admins.add(self.other_django_user)
|
||||
self.organizations[0].projects.add(a_new_proj)
|
||||
proj_detail = reverse('api:project_detail', args=(a_new_proj.pk,))
|
||||
self.patch(proj_detail, data=dict(description="test"), expect=200, auth=self.get_other_credentials())
|
||||
self.organizations[0].admins.remove(self.other_django_user)
|
||||
self.patch(proj_detail, data=dict(description="test_now"), expect=403, auth=self.get_other_credentials())
|
||||
self.delete(proj_detail, expect=403, auth=self.get_other_credentials())
|
||||
a_new_proj.delete()
|
||||
|
||||
# =====================================================================
|
||||
# TEAMS
|
||||
|
||||
|
||||
@ -426,6 +426,8 @@ class JobCallbackModule(BaseCallbackModule):
|
||||
def v2_playbook_on_stats(self, stats):
|
||||
self.playbook_on_stats(stats)
|
||||
|
||||
def v2_playbook_on_include(self, included_file):
|
||||
self._log_event('playbook_on_include', included_file=included_file)
|
||||
|
||||
class AdHocCommandCallbackModule(BaseCallbackModule):
|
||||
'''
|
||||
|
||||
@ -35,7 +35,10 @@ import time
|
||||
import datetime
|
||||
from copy import deepcopy
|
||||
from ansible import constants as C
|
||||
from ansible.cache.base import BaseCacheModule
|
||||
try:
|
||||
from ansible.cache.base import BaseCacheModule
|
||||
except:
|
||||
from ansible.plugins.cache.base import BaseCacheModule
|
||||
|
||||
try:
|
||||
import zmq
|
||||
@ -46,7 +49,6 @@ except ImportError:
|
||||
class CacheModule(BaseCacheModule):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
# Basic in-memory caching for typical runs
|
||||
self._cache = {}
|
||||
self._cache_prev = {}
|
||||
@ -108,16 +110,15 @@ class CacheModule(BaseCacheModule):
|
||||
module = self.identify_new_module(key, value)
|
||||
# Assume ansible fact triggered the set if no new module found
|
||||
facts = self.filter_ansible_facts(value) if not module else dict({ module : value[module]})
|
||||
|
||||
self._cache_prev = deepcopy(self._cache)
|
||||
self._cache[key] = value
|
||||
|
||||
self._cache_prev = deepcopy(self._cache)
|
||||
packet = {
|
||||
'host': key,
|
||||
'inventory_id': os.environ['INVENTORY_ID'],
|
||||
'facts': facts,
|
||||
'date_key': self.date_key,
|
||||
}
|
||||
|
||||
# Emit fact data to tower for processing
|
||||
self.socket.send_json(packet)
|
||||
self.socket.recv()
|
||||
|
||||
@ -66,7 +66,7 @@ Examples:
|
||||
$ ansible -i gce.py us-central1-a -m shell -a "/bin/uname -a"
|
||||
|
||||
Use the GCE inventory script to print out instance specific information
|
||||
$ plugins/inventory/gce.py --host my_instance
|
||||
$ contrib/inventory/gce.py --host my_instance
|
||||
|
||||
Author: Eric Johnson <erjohnso@google.com>
|
||||
Version: 0.0.1
|
||||
@ -112,9 +112,9 @@ class GceInventory(object):
|
||||
|
||||
# Just display data for specific host
|
||||
if self.args.host:
|
||||
print self.json_format_dict(self.node_to_dict(
|
||||
print(self.json_format_dict(self.node_to_dict(
|
||||
self.get_instance(self.args.host)),
|
||||
pretty=self.args.pretty)
|
||||
pretty=self.args.pretty))
|
||||
sys.exit(0)
|
||||
|
||||
# Otherwise, assume user wants all instances grouped
|
||||
@ -237,7 +237,7 @@ class GceInventory(object):
|
||||
'''Gets details about a specific instance '''
|
||||
try:
|
||||
return self.driver.ex_get_node(instance_name)
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
return None
|
||||
|
||||
def group_instances(self):
|
||||
@ -257,7 +257,10 @@ class GceInventory(object):
|
||||
|
||||
tags = node.extra['tags']
|
||||
for t in tags:
|
||||
tag = 'tag_%s' % t
|
||||
if t.startswith('group-'):
|
||||
tag = t[6:]
|
||||
else:
|
||||
tag = 'tag_%s' % t
|
||||
if groups.has_key(tag): groups[tag].append(name)
|
||||
else: groups[tag] = [name]
|
||||
|
||||
|
||||
@ -153,6 +153,8 @@ import warnings
|
||||
import collections
|
||||
import ConfigParser
|
||||
|
||||
from six import iteritems
|
||||
|
||||
from ansible.constants import get_config, mk_boolean
|
||||
|
||||
try:
|
||||
@ -167,6 +169,9 @@ except ImportError:
|
||||
print('pyrax is required for this module')
|
||||
sys.exit(1)
|
||||
|
||||
from time import time
|
||||
|
||||
|
||||
NON_CALLABLES = (basestring, bool, dict, int, list, type(None))
|
||||
|
||||
|
||||
@ -214,7 +219,7 @@ def host(regions, hostname):
|
||||
print(json.dumps(hostvars, sort_keys=True, indent=4))
|
||||
|
||||
|
||||
def _list(regions):
|
||||
def _list_into_cache(regions):
|
||||
groups = collections.defaultdict(list)
|
||||
hostvars = collections.defaultdict(dict)
|
||||
images = {}
|
||||
@ -242,7 +247,7 @@ def _list(regions):
|
||||
if cs is None:
|
||||
warnings.warn(
|
||||
'Connecting to Rackspace region "%s" has caused Pyrax to '
|
||||
'return a NoneType. Is this a valid region?' % region,
|
||||
'return None. Is this a valid region?' % region,
|
||||
RuntimeWarning)
|
||||
continue
|
||||
for server in cs.servers.list():
|
||||
@ -264,7 +269,7 @@ def _list(regions):
|
||||
|
||||
hostvars[server.name]['rax_region'] = region
|
||||
|
||||
for key, value in server.metadata.iteritems():
|
||||
for key, value in iteritems(server.metadata):
|
||||
groups['%s_%s_%s' % (prefix, key, value)].append(server.name)
|
||||
|
||||
groups['instance-%s' % server.id].append(server.name)
|
||||
@ -334,7 +339,31 @@ def _list(regions):
|
||||
|
||||
if hostvars:
|
||||
groups['_meta'] = {'hostvars': hostvars}
|
||||
print(json.dumps(groups, sort_keys=True, indent=4))
|
||||
|
||||
with open(get_cache_file_path(regions), 'w') as cache_file:
|
||||
json.dump(groups, cache_file)
|
||||
|
||||
|
||||
def get_cache_file_path(regions):
|
||||
regions_str = '.'.join([reg.strip().lower() for reg in regions])
|
||||
ansible_tmp_path = os.path.join(os.path.expanduser("~"), '.ansible', 'tmp')
|
||||
if not os.path.exists(ansible_tmp_path):
|
||||
os.makedirs(ansible_tmp_path)
|
||||
return os.path.join(ansible_tmp_path,
|
||||
'ansible-rax-%s-%s.cache' % (
|
||||
pyrax.identity.username, regions_str))
|
||||
|
||||
|
||||
def _list(regions, refresh_cache=True):
|
||||
if (not os.path.exists(get_cache_file_path(regions)) or
|
||||
refresh_cache or
|
||||
(time() - os.stat(get_cache_file_path(regions))[-1]) > 600):
|
||||
# Cache file doesn't exist or older than 10m or refresh cache requested
|
||||
_list_into_cache(regions)
|
||||
|
||||
with open(get_cache_file_path(regions), 'r') as cache_file:
|
||||
groups = json.load(cache_file)
|
||||
print(json.dumps(groups, sort_keys=True, indent=4))
|
||||
|
||||
|
||||
def parse_args():
|
||||
@ -344,6 +373,9 @@ def parse_args():
|
||||
group.add_argument('--list', action='store_true',
|
||||
help='List active servers')
|
||||
group.add_argument('--host', help='List details about the specific host')
|
||||
parser.add_argument('--refresh-cache', action='store_true', default=False,
|
||||
help=('Force refresh of cache, making API requests to'
|
||||
'RackSpace (default: False - use cache files)'))
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
@ -382,7 +414,7 @@ def setup():
|
||||
pyrax.keyring_auth(keyring_username, region=region)
|
||||
else:
|
||||
pyrax.set_credential_file(creds_file, region=region)
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
sys.stderr.write("%s: %s\n" % (e, e.message))
|
||||
sys.exit(1)
|
||||
|
||||
@ -410,7 +442,7 @@ def main():
|
||||
args = parse_args()
|
||||
regions = setup()
|
||||
if args.list:
|
||||
_list(regions)
|
||||
_list(regions, refresh_cache=args.refresh_cache)
|
||||
elif args.host:
|
||||
host(regions, args.host)
|
||||
sys.exit(0)
|
||||
|
||||
@ -28,6 +28,8 @@ take precedence over options present in the INI file. An INI file is not
|
||||
required if these options are specified using environment variables.
|
||||
'''
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import collections
|
||||
import json
|
||||
import logging
|
||||
@ -37,6 +39,8 @@ import sys
|
||||
import time
|
||||
import ConfigParser
|
||||
|
||||
from six import text_type
|
||||
|
||||
# Disable logging message trigged by pSphere/suds.
|
||||
try:
|
||||
from logging import NullHandler
|
||||
@ -95,7 +99,7 @@ class VMwareInventory(object):
|
||||
Saves the value to cache with the name given.
|
||||
'''
|
||||
if self.config.has_option('defaults', 'cache_dir'):
|
||||
cache_dir = self.config.get('defaults', 'cache_dir')
|
||||
cache_dir = os.path.expanduser(self.config.get('defaults', 'cache_dir'))
|
||||
if not os.path.exists(cache_dir):
|
||||
os.makedirs(cache_dir)
|
||||
cache_file = os.path.join(cache_dir, name)
|
||||
@ -115,7 +119,7 @@ class VMwareInventory(object):
|
||||
else:
|
||||
cache_max_age = 0
|
||||
cache_stat = os.stat(cache_file)
|
||||
if (cache_stat.st_mtime + cache_max_age) < time.time():
|
||||
if (cache_stat.st_mtime + cache_max_age) >= time.time():
|
||||
with open(cache_file) as cache:
|
||||
return json.load(cache)
|
||||
return default
|
||||
@ -147,7 +151,7 @@ class VMwareInventory(object):
|
||||
seen = seen or set()
|
||||
if isinstance(obj, ManagedObject):
|
||||
try:
|
||||
obj_unicode = unicode(getattr(obj, 'name'))
|
||||
obj_unicode = text_type(getattr(obj, 'name'))
|
||||
except AttributeError:
|
||||
obj_unicode = ()
|
||||
if obj in seen:
|
||||
@ -164,7 +168,7 @@ class VMwareInventory(object):
|
||||
obj_info = self._get_obj_info(val, depth - 1, seen)
|
||||
if obj_info != ():
|
||||
d[attr] = obj_info
|
||||
except Exception, e:
|
||||
except Exception as e:
|
||||
pass
|
||||
return d
|
||||
elif isinstance(obj, SudsObject):
|
||||
@ -207,8 +211,8 @@ class VMwareInventory(object):
|
||||
host_info[k] = v
|
||||
try:
|
||||
host_info['ipAddress'] = host.config.network.vnic[0].spec.ip.ipAddress
|
||||
except Exception, e:
|
||||
print >> sys.stderr, e
|
||||
except Exception as e:
|
||||
print(e, file=sys.stderr)
|
||||
host_info = self._flatten_dict(host_info, prefix)
|
||||
if ('%s_ipAddress' % prefix) in host_info:
|
||||
host_info['ansible_ssh_host'] = host_info['%s_ipAddress' % prefix]
|
||||
|
||||
@ -51,7 +51,7 @@ try:
|
||||
from azure import WindowsAzureError
|
||||
from azure.servicemanagement import ServiceManagementService
|
||||
except ImportError as e:
|
||||
print "failed=True msg='`azure` library required for this script'"
|
||||
print("failed=True msg='`azure` library required for this script'")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@ -70,8 +70,8 @@ class AzureInventory(object):
|
||||
# Cache setting defaults.
|
||||
# These can be overridden in settings (see `read_settings`).
|
||||
cache_dir = os.path.expanduser('~')
|
||||
self.cache_path_cache = '%s/.ansible-azure.cache' % cache_dir
|
||||
self.cache_path_index = '%s/.ansible-azure.index' % cache_dir
|
||||
self.cache_path_cache = os.path.join(cache_dir, '.ansible-azure.cache')
|
||||
self.cache_path_index = os.path.join(cache_dir, '.ansible-azure.index')
|
||||
self.cache_max_age = 0
|
||||
|
||||
# Read settings and parse CLI arguments
|
||||
@ -103,15 +103,13 @@ class AzureInventory(object):
|
||||
# Add the `['_meta']['hostvars']` information.
|
||||
hostvars = {}
|
||||
if len(data) > 0:
|
||||
for host in set(reduce(lambda x, y: x + y,
|
||||
[i for i in data.values()])):
|
||||
if host is not None:
|
||||
hostvars[host] = self.get_host(host, jsonify=False)
|
||||
for host in set([h for hosts in data.values() for h in hosts if h]):
|
||||
hostvars[host] = self.get_host(host, jsonify=False)
|
||||
data['_meta'] = {'hostvars': hostvars}
|
||||
|
||||
# JSONify the data.
|
||||
data_to_print = self.json_format_dict(data, pretty=True)
|
||||
print data_to_print
|
||||
print(data_to_print)
|
||||
|
||||
def get_host(self, hostname, jsonify=True):
|
||||
"""Return information about the given hostname, based on what
|
||||
@ -153,9 +151,9 @@ class AzureInventory(object):
|
||||
|
||||
# Cache related
|
||||
if config.has_option('azure', 'cache_path'):
|
||||
cache_path = os.path.expanduser(config.get('azure', 'cache_path'))
|
||||
self.cache_path_cache = cache_path + '/ansible-azure.cache'
|
||||
self.cache_path_index = cache_path + '/ansible-azure.index'
|
||||
cache_path = os.path.expandvars(os.path.expanduser(config.get('azure', 'cache_path')))
|
||||
self.cache_path_cache = os.path.join(cache_path, 'ansible-azure.cache')
|
||||
self.cache_path_index = os.path.join(cache_path, 'ansible-azure.index')
|
||||
if config.has_option('azure', 'cache_max_age'):
|
||||
self.cache_max_age = config.getint('azure', 'cache_max_age')
|
||||
|
||||
@ -197,9 +195,9 @@ class AzureInventory(object):
|
||||
for cloud_service in self.sms.list_hosted_services():
|
||||
self.add_deployments(cloud_service)
|
||||
except WindowsAzureError as e:
|
||||
print "Looks like Azure's API is down:"
|
||||
print
|
||||
print e
|
||||
print("Looks like Azure's API is down:")
|
||||
print("")
|
||||
print(e)
|
||||
sys.exit(1)
|
||||
|
||||
def add_deployments(self, cloud_service):
|
||||
@ -209,12 +207,10 @@ class AzureInventory(object):
|
||||
try:
|
||||
for deployment in self.sms.get_hosted_service_properties(cloud_service.service_name,embed_detail=True).deployments.deployments:
|
||||
self.add_deployment(cloud_service, deployment)
|
||||
#if deployment.deployment_slot == "Production":
|
||||
# self.add_deployment(cloud_service, deployment)
|
||||
except WindowsAzureError as e:
|
||||
print "Looks like Azure's API is down:"
|
||||
print
|
||||
print e
|
||||
print("Looks like Azure's API is down:")
|
||||
print("")
|
||||
print(e)
|
||||
sys.exit(1)
|
||||
|
||||
def add_deployment(self, cloud_service, deployment):
|
||||
|
||||
@ -448,6 +448,9 @@ AWX_JOB_TEMPLATE_HISTORY = 10
|
||||
# The directory in which proot will create new temporary directories for its root
|
||||
AWX_PROOT_BASE_PATH = "/tmp"
|
||||
|
||||
# User definable ansible callback plugins
|
||||
AWX_ANSIBLE_CALLBACK_PLUGINS = ""
|
||||
|
||||
# Enable Pendo on the UI, possible values are 'off', 'anonymous', and 'detailed'
|
||||
PENDO_TRACKING_STATE = "off"
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
|
||||
{% block style %}
|
||||
{{ block.super }}
|
||||
<link href="{{ STATIC_URL }}img/favicon.ico" rel="shortcut icon" />
|
||||
<link href="{{ STATIC_URL }}assets/favicon.ico" rel="shortcut icon" />
|
||||
<style type="text/css">
|
||||
html body {
|
||||
background: #ddd;
|
||||
@ -183,7 +183,7 @@ html body .dropdown-submenu:hover>a {
|
||||
{% endblock %}
|
||||
|
||||
{% block branding %}
|
||||
<a class="brand" href="/api/"><img class="logo" src="{{ STATIC_URL }}img/tower_console_logo.png">{% block branding_title %}{% trans 'REST API' %}{% endblock %}</a>
|
||||
<a class="brand" href="/api/"><img class="logo" src="{{ STATIC_URL }}assets/tower_console_logo.png">{% block branding_title %}{% trans 'REST API' %}{% endblock %}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block userlinks %}
|
||||
@ -196,7 +196,7 @@ html body .dropdown-submenu:hover>a {
|
||||
|
||||
{% block footer %}
|
||||
<div id="footer">
|
||||
<a href="http://www.ansible.com" target="_blank"><img class="towerlogo" src="{{ STATIC_URL }}img/tower_console_bug.png" /></a><br/>
|
||||
<a href="http://www.ansible.com" target="_blank"><img class="towerlogo" src="{{ STATIC_URL }}assets/tower_console_bug.png" /></a><br/>
|
||||
Copyright © 2015 <a href="http://www.ansible.com" target="_blank">Ansible, Inc.</a> All rights reserved.
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@ -187,6 +187,9 @@ var tower = angular.module('Tower', [
|
||||
.constant('AngularScheduler.useTimezone', true)
|
||||
.constant('AngularScheduler.showUTCField', true)
|
||||
.constant('$timezones.definitions.location', urlPrefix + 'lib/angular-tz-extensions/tz/data')
|
||||
.config(['$pendolyticsProvider', function($pendolyticsProvider) {
|
||||
$pendolyticsProvider.doNotAutoStart();
|
||||
}])
|
||||
.config(['$routeProvider',
|
||||
function ($routeProvider) {
|
||||
$routeProvider.
|
||||
@ -989,7 +992,7 @@ var tower = angular.module('Tower', [
|
||||
if (next.templateUrl !== (urlPrefix + 'login/loginBackDrop.partial.html')) {
|
||||
$location.path('/login');
|
||||
}
|
||||
} else if ($rootScope.sessionTimer.isExpired()) {
|
||||
} else if ($rootScope && $rootScope.sessionTimer && $rootScope.sessionTimer.isExpired()) {
|
||||
// gets here on timeout
|
||||
if (next.templateUrl !== (urlPrefix + 'login/loginBackDrop.partial.html')) {
|
||||
$rootScope.sessionTimer.expireSession('idle');
|
||||
@ -1019,7 +1022,7 @@ var tower = angular.module('Tower', [
|
||||
// If browser refresh, set the user_is_superuser value
|
||||
$rootScope.user_is_superuser = Authorization.getUserInfo('is_superuser');
|
||||
// when the user refreshes we want to open the socket, except if the user is on the login page, which should happen after the user logs in (see the AuthService module for that call to OpenSocket)
|
||||
if($location.$$url !== '/login'){
|
||||
if(!_.contains($location.$$url, '/login')){
|
||||
$rootScope.sessionTimer = Timer.init();
|
||||
$rootScope.$emit('OpenSocket');
|
||||
pendoService.issuePendoIdentity();
|
||||
|
||||
@ -27,6 +27,14 @@ export function JobDetailController ($location, $rootScope, $filter, $scope, $co
|
||||
|
||||
scope.plays = [];
|
||||
|
||||
scope.$watch('job_status', function(job_status) {
|
||||
if (job_status && job_status.explanation && job_status.explanation.split(":")[0] === "Previous Task Failed") {
|
||||
var taskObj = JSON.parse(job_status.explanation.substring(job_status.explanation.split(":")[0].length + 1));
|
||||
job_status.explanation = job_status.explanation.split(":")[0] + ". ";
|
||||
job_status.explanation += "<code>" + taskObj.task_type + "-" + taskObj.task_id + " failed for " + taskObj.task_name + "</code>"
|
||||
}
|
||||
}, true);
|
||||
|
||||
scope.$watch('plays', function(plays) {
|
||||
for (var play in plays) {
|
||||
if (plays[play].elapsed) {
|
||||
|
||||
@ -105,16 +105,14 @@ export function JobStdoutController ($location, $log, $rootScope, $scope, $compi
|
||||
api_complete = true;
|
||||
$('#pre-container-content').html(data.content);
|
||||
current_range = data.range;
|
||||
loaded_sections.push({
|
||||
start: (data.range.start < 0) ? 0 : data.range.start,
|
||||
end: data.range.end
|
||||
});
|
||||
|
||||
//console.log('loaded start: ' + data.range.start + ' end: ' + data.range.end);
|
||||
//console.log(data.content);
|
||||
if (data.content !== "Waiting for results...") {
|
||||
loaded_sections.push({
|
||||
start: (data.range.start < 0) ? 0 : data.range.start,
|
||||
end: data.range.end
|
||||
});
|
||||
}
|
||||
|
||||
$('#pre-container').scrollTop($('#pre-container').prop("scrollHeight"));
|
||||
//console.log($('#pre-container-content').prop("scrollHeight"));
|
||||
}
|
||||
else {
|
||||
api_complete = true;
|
||||
@ -158,6 +156,8 @@ export function JobStdoutController ($location, $log, $rootScope, $scope, $compi
|
||||
}
|
||||
};
|
||||
|
||||
$(".StandardOut").height($("body").height() - 60);
|
||||
|
||||
// Note: could be ad_hoc_commands or jobs
|
||||
var jobType = $location.path().replace(/^\//, '').split('/')[0];
|
||||
Rest.setUrl(GetBasePath(jobType) + job_id + '/');
|
||||
|
||||
@ -46,8 +46,10 @@ export default
|
||||
sourceModel: 'credential',
|
||||
sourceField: 'name',
|
||||
ngClick: 'lookUpCredential()',
|
||||
addRequired: false,
|
||||
editRequired: false
|
||||
awRequiredWhen: {
|
||||
variable: "cloudCredentialRequired",
|
||||
init: "false"
|
||||
}
|
||||
},
|
||||
source_regions: {
|
||||
label: 'Regions',
|
||||
|
||||
@ -47,6 +47,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name
|
||||
});
|
||||
}
|
||||
}
|
||||
scope.cloudCredentialRequired = false;
|
||||
scope.$emit('sourceTypeOptionsReady');
|
||||
})
|
||||
.error(function (data, status) {
|
||||
@ -243,6 +244,8 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name
|
||||
form = params.form,
|
||||
kind, url, callback, invUrl;
|
||||
|
||||
scope.cloudCredentialRequired = false;
|
||||
|
||||
if (!Empty(scope.source)) {
|
||||
if (scope.source.value === 'file') {
|
||||
scope.sourcePathRequired = true;
|
||||
@ -283,7 +286,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name
|
||||
}
|
||||
if(scope.source.value==="custom"){
|
||||
// need to filter the possible custom scripts by the organization defined for the current inventory
|
||||
invUrl = GetBasePath('inventory_scripts') + '?organization='+scope.$parent.inventory.organization;
|
||||
invUrl = GetBasePath('inventory_scripts');
|
||||
LookUpInit({
|
||||
url: invUrl,
|
||||
scope: scope,
|
||||
@ -313,6 +316,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name
|
||||
kind = 'aws';
|
||||
} else {
|
||||
kind = scope.source.value;
|
||||
scope.cloudCredentialRequired = true;
|
||||
}
|
||||
url = GetBasePath('credentials') + '?cloud=true&kind=' + kind;
|
||||
LookUpInit({
|
||||
@ -1030,9 +1034,17 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name
|
||||
else if(fld === "inventory_script"){
|
||||
// the API stores it as 'source_script', we call it inventory_script
|
||||
data.summary_fields['inventory_script'] = data.summary_fields.source_script;
|
||||
}
|
||||
|
||||
else if (data[fld] !== undefined) {
|
||||
sources_scope.inventory_script = data.source_script;
|
||||
master.inventory_script = sources_scope.inventory_script;
|
||||
} else if (fld === "source_regions") {
|
||||
if (data[fld] === "") {
|
||||
sources_scope[fld] = data[fld];
|
||||
master[fld] = sources_scope[fld];
|
||||
} else {
|
||||
sources_scope[fld] = data[fld].split(",");
|
||||
master[fld] = sources_scope[fld];
|
||||
}
|
||||
} else if (data[fld] !== undefined) {
|
||||
sources_scope[fld] = data[fld];
|
||||
master[fld] = sources_scope[fld];
|
||||
}
|
||||
@ -1392,7 +1404,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name
|
||||
if (mode === 'edit' || (mode === 'add' && group_created)) {
|
||||
Rest.put(data)
|
||||
.success(function () {
|
||||
if (properties_scope.variables) {
|
||||
if (properties_scope.variables && properties_scope.variables !== "---") {
|
||||
modal_scope.$emit('updateVariables', json_data, properties_scope.variable_url);
|
||||
}
|
||||
else {
|
||||
|
||||
@ -99,7 +99,8 @@ export default
|
||||
promise.then(function (response) {
|
||||
config = response.license_info;
|
||||
config.analytics_status = response.analytics_status;
|
||||
if(config.analytics_status !== 'off'){
|
||||
if(config.analytics_status === 'detailed' || config.analytics_status === 'anonymous'){
|
||||
$pendolytics.bootstrap();
|
||||
deferred.resolve(config);
|
||||
}
|
||||
else {
|
||||
@ -114,7 +115,8 @@ export default
|
||||
deferred.reject('Could not resolve pendo config.');
|
||||
});
|
||||
}
|
||||
else if(config.analytics_status !== 'off'){
|
||||
else if(config.analytics_status === 'detailed' || config.analytics_status === 'anonymous'){
|
||||
$pendolytics.bootstrap();
|
||||
deferred.resolve(config);
|
||||
}
|
||||
else {
|
||||
@ -128,6 +130,8 @@ export default
|
||||
this.getConfig().then(function(config){
|
||||
var options = that.setPendoOptions(config);
|
||||
that.setRole(options).then(function(options){
|
||||
$log.debug('Pendo status is '+ config.analytics_status + '. Object below:');
|
||||
$log.debug(options);
|
||||
$pendolytics.identify(options);
|
||||
}, function(reason){
|
||||
// reject function for setRole
|
||||
|
||||
@ -23,23 +23,35 @@
|
||||
*/
|
||||
export default
|
||||
['$rootScope', '$cookieStore', 'transitionTo', 'CreateDialog', 'Authorization',
|
||||
function ($rootScope, $cookieStore, transitionTo, CreateDialog, Authorization) {
|
||||
'Store', '$interval',
|
||||
function ($rootScope, $cookieStore, transitionTo, CreateDialog, Authorization,
|
||||
Store, $interval) {
|
||||
return {
|
||||
|
||||
sessionTime: null,
|
||||
timeout: null,
|
||||
|
||||
getSessionTime: function () {
|
||||
return (this.sessionTime) ? this.sessionTime : $cookieStore.get('sessionTime');
|
||||
if(Store('sessionTime_'+$rootScope.current_user.id)){
|
||||
return Store('sessionTime_'+$rootScope.current_user.id);
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
isExpired: function () {
|
||||
isExpired: function (increase) {
|
||||
var stime = this.getSessionTime(),
|
||||
now = new Date().getTime();
|
||||
if ((stime - now) <= 0) {
|
||||
//expired
|
||||
return true;
|
||||
} else {
|
||||
}
|
||||
else if(increase){
|
||||
return false;
|
||||
}
|
||||
else{
|
||||
// not expired. move timer forward.
|
||||
this.moveForward();
|
||||
return false;
|
||||
@ -52,7 +64,7 @@ export default
|
||||
diff = stime-now;
|
||||
|
||||
if(diff < 61){
|
||||
return true;
|
||||
return diff;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
@ -76,76 +88,74 @@ export default
|
||||
|
||||
moveForward: function () {
|
||||
var tm, t;
|
||||
tm = ($AnsibleConfig) ? $AnsibleConfig.session_timeout : 1800;
|
||||
tm = ($AnsibleConfig.session_timeout) ? $AnsibleConfig.session_timeout : 1800;
|
||||
t = new Date().getTime() + (tm * 1000);
|
||||
this.sessionTime = t;
|
||||
$cookieStore.put('sessionTime', t);
|
||||
Store('sessionTime_'+$rootScope.current_user.id, t);
|
||||
$rootScope.sessionExpired = false;
|
||||
$cookieStore.put('sessionExpired', false);
|
||||
|
||||
this.startTimers();
|
||||
},
|
||||
|
||||
startTimers: function() {
|
||||
var that = this,
|
||||
tm = ($AnsibleConfig) ? $AnsibleConfig.session_timeout : 1800,
|
||||
t = tm - 60;
|
||||
|
||||
startTimers: function(){
|
||||
var that = this;
|
||||
this.clearTimers();
|
||||
|
||||
// make a timeout that will go off in 30 mins to log them out
|
||||
// unless they extend their time
|
||||
$rootScope.endTimer = setTimeout(function(){
|
||||
that.expireSession('idle');
|
||||
}, tm * 1000);
|
||||
|
||||
// notify the user a minute before the end of their session that
|
||||
// their session is about to expire
|
||||
if($rootScope.idleTimer){
|
||||
clearTimeout($rootScope.idleTimer);
|
||||
}
|
||||
$rootScope.idleTimer = setTimeout(function() {
|
||||
if(that.isIdle() === true){
|
||||
var buttons = [{
|
||||
"label": "Continue",
|
||||
"onClick": function() {
|
||||
// make a rest call here to force the API to
|
||||
// move the session time forward
|
||||
Authorization.getUser();
|
||||
that.moveForward();
|
||||
$(this).dialog('close');
|
||||
|
||||
},
|
||||
"class": "btn btn-primary",
|
||||
"id": "idle-modal-button"
|
||||
}];
|
||||
|
||||
if ($rootScope.removeIdleDialogReady) {
|
||||
$rootScope.removeIdleDialogReady();
|
||||
$rootScope.expireTimer = $interval(function() {
|
||||
var idle = that.isIdle();
|
||||
if(idle !== false){
|
||||
if($('#idle-modal').is(':visible')){
|
||||
$('#remaining_seconds').html(Math.round(idle));
|
||||
}
|
||||
$rootScope.removeIdleDialogReady = $rootScope.$on('IdleDialogReady', function() {
|
||||
$('#idle-modal').show();
|
||||
$('#idle-modal').dialog('open');
|
||||
});
|
||||
CreateDialog({
|
||||
id: 'idle-modal' ,
|
||||
title: "Idle Session",
|
||||
scope: $rootScope,
|
||||
buttons: buttons,
|
||||
width: 470,
|
||||
height: 240,
|
||||
minWidth: 200,
|
||||
callback: 'IdleDialogReady'
|
||||
});
|
||||
}
|
||||
}, t * 1000);
|
||||
else {
|
||||
var buttons = [{
|
||||
"label": "Continue",
|
||||
"onClick": function() {
|
||||
// make a rest call here to force the API to
|
||||
// move the session time forward
|
||||
Authorization.getUser();
|
||||
that.moveForward();
|
||||
$(this).dialog('close');
|
||||
},
|
||||
"class": "btn btn-primary",
|
||||
"id": "idle-modal-button"
|
||||
}];
|
||||
|
||||
if ($rootScope.removeIdleDialogReady) {
|
||||
$rootScope.removeIdleDialogReady();
|
||||
}
|
||||
$rootScope.removeIdleDialogReady = $rootScope.$on('IdleDialogReady', function() {
|
||||
$('#idle-modal').show();
|
||||
$('#idle-modal').dialog('open');
|
||||
});
|
||||
CreateDialog({
|
||||
id: 'idle-modal' ,
|
||||
title: "Idle Session",
|
||||
scope: $rootScope,
|
||||
buttons: buttons,
|
||||
width: 470,
|
||||
height: 240,
|
||||
minWidth: 200,
|
||||
callback: 'IdleDialogReady'
|
||||
});
|
||||
}
|
||||
}
|
||||
else if(!idle){
|
||||
if($('#idle-modal').is(':visible')){
|
||||
$('#idle-modal').dialog('close');
|
||||
}
|
||||
}
|
||||
if (that.isExpired(true)) {
|
||||
if($('#idle-modal').dialog('isOpen')){
|
||||
$('#idle-modal').dialog('close');
|
||||
}
|
||||
that.expireSession('idle');
|
||||
}
|
||||
|
||||
}, 1000);
|
||||
|
||||
},
|
||||
|
||||
clearTimers: function(){
|
||||
clearTimeout($rootScope.idleTimer);
|
||||
clearTimeout($rootScope.endTimer);
|
||||
$interval.cancel($rootScope.expireTimer);
|
||||
},
|
||||
|
||||
init: function () {
|
||||
|
||||
@ -165,6 +165,7 @@ export default ['$log', '$cookieStore', '$compile', '$window', '$rootScope', '$l
|
||||
Authorization.getUser()
|
||||
.success(function (data) {
|
||||
Authorization.setUserInfo(data);
|
||||
$rootScope.sessionTimer = Timer.init();
|
||||
$rootScope.user_is_superuser = data.results[0].is_superuser;
|
||||
scope.$emit('AuthorizationGetLicense');
|
||||
})
|
||||
@ -187,7 +188,6 @@ export default ['$log', '$cookieStore', '$compile', '$window', '$rootScope', '$l
|
||||
.then(function (data) {
|
||||
$('#login-modal').modal('hide');
|
||||
Authorization.setToken(data.data.token, data.data.expires);
|
||||
$rootScope.sessionTimer = Timer.init();
|
||||
scope.$emit('AuthorizationGetUser');
|
||||
},
|
||||
function (data) {
|
||||
|
||||
@ -1,47 +1,42 @@
|
||||
<div class="tab-pane" id="jobs-stdout">
|
||||
<div ng-cloak id="htmlTemplate">
|
||||
|
||||
<div class="row">
|
||||
<div id="breadcrumb-container" class="col-md-6" style="position: relative;">
|
||||
<ul class="ansible-breadcrumb" id="breadcrumb-list">
|
||||
<li><a href="/#/jobs">Jobs</a></li>
|
||||
<li><a href="/#/jobs/{{ job.id }}">{{ job.id }} - {{ job.name }}</a></li>
|
||||
<li class="active"><a href="">Standard Out</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="home-list-actions" class="list-actions pull-right col-md-6">
|
||||
<button type="button" class="btn btn-xs btn-primary ng-hide" ng-click="refresh()" id="refresh_btn" aw-tool-tip="Refresh the page" data-placement="top" ng-show="socketStatus == 'error'" data-original-title="" title=""><i class="fa fa-refresh fa-lg"></i> </button></div>
|
||||
<div class="StandardOut">
|
||||
<div class="StandardOut-heading">
|
||||
|
||||
<div class="row StandardOut-breadcrumbs">
|
||||
<div id="breadcrumb-container" class="col-md-6" style="position: relative;">
|
||||
<ul class="ansible-breadcrumb" id="breadcrumb-list">
|
||||
<li><a href="/#/jobs">Jobs</a></li>
|
||||
<li><a href="/#/jobs/{{ job.id }}">{{ job.id }} - {{ job.name }}</a></li>
|
||||
<li class="active"><a href="">Standard Out</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="home-list-actions" class="list-actions pull-right col-md-6">
|
||||
<button type="button" class="btn btn-xs btn-primary ng-hide" ng-click="refresh()" id="refresh_btn" aw-tool-tip="Refresh the page" data-placement="top" ng-show="socketStatus == 'error'" data-original-title="" title=""><i class="fa fa-refresh fa-lg"></i> </button></div>
|
||||
</div>
|
||||
<div class="row StandardOut-form">
|
||||
<div class="col-md-12">
|
||||
<div id="job-status"><label>Job Status</label> <i class="fa icon-job-{{ job.status }}"></i> {{ job.status }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div id="job-status"><label>Job Status</label> <i class="fa icon-job-{{ job.status }}"></i> {{ job.status }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="panel panel-default job-stdout-panel">
|
||||
<div class="panel-heading">
|
||||
<div class="panel panel-default job-stdout-panel StandardOut-panel">
|
||||
<div class="panel-heading StandardOut-panelHeading">
|
||||
<h3 class="panel-title">Standard Output
|
||||
<a href="/api/v1/jobs/{{ job.id }}/stdout?format=txt_download&token={{ token }}" class="btn btn-primary btn-xs DownloadStandardOut DownloadStandardOut--onStandardOutPage" id="download-stdout-button" type="button" aw-tool-tip="Download standard out as a .txt file" data-placement="top" ng-show="job.status === 'cancelled' || job.status === 'failed' || job.status === 'error' || job.status === 'successful'">
|
||||
<i class="fa fa-download DownloadStandardOut-icon DownloadStandardOut-icon--withText"></i>Download
|
||||
</a>
|
||||
</div>
|
||||
<div class="panel-body stdout-panel-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="scroll-spinner" id="stdoutMoreRowsTop">
|
||||
<i class="fa fa-cog fa-spin"></i>
|
||||
</div>
|
||||
<div id="pre-container" class="body_background
|
||||
body_foreground pre mono-space"
|
||||
lr-infinite-scroll="stdOutScrollToTop"
|
||||
scroll-threshold="300" data-direction="up" time-threshold="500">
|
||||
<div id="pre-container-content"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="scroll-spinner" id="stdoutMoreRowsBottom">
|
||||
<i class="fa fa-cog fa-spin"></i>
|
||||
</div>
|
||||
<div class="panel-body stdout-panel-body StandardOut-panelBody">
|
||||
<div id="pre-container" class="body_background
|
||||
body_foreground pre mono-space StandardOut-preContainer"
|
||||
lr-infinite-scroll="stdOutScrollToTop"
|
||||
scroll-threshold="300" data-direction="up" time-threshold="500">
|
||||
<div id="pre-container-content" class="StandardOut-preContent"></div>
|
||||
</div>
|
||||
<div class="scroll-spinner" id="stdoutMoreRowsBottom">
|
||||
<i class="fa fa-cog fa-spin"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,187 +1,183 @@
|
||||
<div class="tab-pane" id="jobs-stdout">
|
||||
<div ng-cloak id="htmlTemplate">
|
||||
|
||||
<div class="row">
|
||||
<div id="breadcrumb-container" class="col-md-6"
|
||||
style="position: relative;">
|
||||
<ul class="ansible-breadcrumb" id="breadcrumb-list">
|
||||
<li><a href="/#/jobs">Jobs</a></li>
|
||||
<li class="active">
|
||||
<a href="/#/ad_hoc_commands/{{ job.id }}">
|
||||
{{ job.id }} - {{ job.name }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="StandardOut">
|
||||
<div class="row StandardOut-heading">
|
||||
<div class="row StandardOut-breadcrumbs">
|
||||
<div id="breadcrumb-container" class="col-md-6"
|
||||
style="position: relative;">
|
||||
<ul class="ansible-breadcrumb" id="breadcrumb-list">
|
||||
<li><a href="/#/jobs">Jobs</a></li>
|
||||
<li class="active">
|
||||
<a href="/#/ad_hoc_commands/{{ job.id }}">
|
||||
{{ job.id }} - {{ job.name }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div id="home-list-actions"
|
||||
class="list-actions pull-right col-md-6">
|
||||
<button type="button" class="btn btn-xs btn-primary ng-hide"
|
||||
ng-click="refresh()" id="refresh_btn"
|
||||
aw-tool-tip="Refresh the page"
|
||||
data-placement="top" ng-show="socketStatus == 'error'"
|
||||
data-original-title="" title="">
|
||||
<i class="fa fa-refresh fa-lg"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="home-list-actions"
|
||||
class="list-actions pull-right col-md-6">
|
||||
<button type="button" class="btn btn-xs btn-primary ng-hide"
|
||||
ng-click="refresh()" id="refresh_btn"
|
||||
aw-tool-tip="Refresh the page"
|
||||
data-placement="top" ng-show="socketStatus == 'error'"
|
||||
data-original-title="" title="">
|
||||
<i class="fa fa-refresh fa-lg"></i>
|
||||
</button>
|
||||
|
||||
<div class="StandardOut-form form-horizontal StandardOutDetails"
|
||||
role="form" id="job-status-form">
|
||||
<div class="form-group StandardOutDetails-detailRow">
|
||||
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-12
|
||||
StandardOutDetails-detailLabel">Status</label>
|
||||
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-12
|
||||
StandardOutDetails-detailContent">
|
||||
<i class="fa icon-job-{{ job.status }}"></i> {{ job.status }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div <div class="form-group StandardOutDetails-detailRow
|
||||
StandardOutDetails-detailRow--closable"
|
||||
ng-show="job.started">
|
||||
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-12
|
||||
StandardOutDetails-detailLabel">Timing</label>
|
||||
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-12
|
||||
StandardOutDetails-detailContent">
|
||||
<div ng-show="job.started" id="started-time">
|
||||
Started {{ job.started | date:'MM/dd/yy HH:mm:ss' }}
|
||||
</div>
|
||||
<div ng-show="job.finished" id="finished-time">
|
||||
Finished {{ job.finished | date:'MM/dd/yy HH:mm:ss' }}
|
||||
</div>
|
||||
<div ng-show="job.finished" id="elapsed-time">
|
||||
Elapsed {{ job.elapsed }} seconds
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div <div class="form-group StandardOutDetails-detailRow
|
||||
StandardOutDetails-detailRow--closable"
|
||||
ng-show="job.module_name">
|
||||
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-12
|
||||
StandardOutDetails-detailLabel">Module Name</label>
|
||||
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-12
|
||||
StandardOutDetails-detailContent">{{ job.module_name }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div <div class="form-group StandardOutDetails-detailRow
|
||||
StandardOutDetails-detailRow--closable"
|
||||
ng-show="job.module_args">
|
||||
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-12
|
||||
StandardOutDetails-detailLabel">Module Args</label>
|
||||
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-12
|
||||
StandardOutDetails-detailContent mono-space">{{ job.module_args }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div <div class="form-group StandardOutDetails-detailRow
|
||||
StandardOutDetails-detailRow--closable"
|
||||
ng-show="inventory_name">
|
||||
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-12
|
||||
StandardOutDetails-detailLabel">Inventory</label>
|
||||
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-12
|
||||
StandardOutDetails-detailContent">
|
||||
<a href="{{ inventory_url }}"
|
||||
aw-tool-tip="The inventory this command ran on."
|
||||
data-placement="top">{{ inventory_name }}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group StandardOutDetails-detailRow
|
||||
StandardOutDetails-detailRow--closable"
|
||||
ng-show="credential_name">
|
||||
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-12
|
||||
StandardOutDetails-detailLabel">Credential</label>
|
||||
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-12
|
||||
StandardOutDetails-detailContent">
|
||||
<a href="{{ credential_url }}"
|
||||
aw-tool-tip="The credential used to run this command."
|
||||
data-placement="top">{{ credential_name }}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group StandardOutDetails-detailRow
|
||||
StandardOutDetails-detailRow--closable"
|
||||
ng-show="created_by">
|
||||
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-12
|
||||
StandardOutDetails-detailContent">Launched By</label>
|
||||
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-9
|
||||
StandardOutDetails-detailContent">
|
||||
<a href="/#/users/{{ created_by.id }}"
|
||||
aw-tool-tip="The user who ran this command."
|
||||
data-placement="top">{{ created_by.username }}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- since zero is a falsy value, you need ng-show such that
|
||||
the number is >= 0 -->
|
||||
<div class="form-group StandardOutDetails-detailRow
|
||||
StandardOutDetails-detailRow--closable"
|
||||
ng-show="forks >= 0">
|
||||
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-12
|
||||
StandardOutDetails-detailLabel">Forks</label>
|
||||
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-12
|
||||
StandardOutDetails-detailContent">{{ forks }}</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group StandardOutDetails-detailRow
|
||||
StandardOutDetails-detailRow--closable"
|
||||
ng-show="limit">
|
||||
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-12
|
||||
StandardOutDetails-detailLabel">Limit</label>
|
||||
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-12
|
||||
StandardOutDetails-detailContent">{{ limit }}</div>
|
||||
</div>
|
||||
|
||||
<!-- since zero is a falsy value, you need ng-show such that
|
||||
the number is >= 0 -->
|
||||
<div class="form-group StandardOutDetails-detailRow
|
||||
StandardOutDetails-detailRow--closable"
|
||||
ng-show="verbosity >= 0">
|
||||
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-12
|
||||
StandardOutDetails-detailLabel">Verbosity</label>
|
||||
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-12
|
||||
StandardOutDetails-detailContent">{{ verbosity }}</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group StandardOutDetails-closedToggle">
|
||||
<a class="col-sm-12 StandardOutDetails-closedToggleLink"
|
||||
ng-show="isClosed" href="javascript:;"
|
||||
ng-click="toggleClosedStatus()"> more <i class="fa fa-angle-down"></i>
|
||||
</a>
|
||||
<a class="col-sm-12 StandardOutDetails-closedToggleLink"
|
||||
ng-show="!isClosed" href="javascript:;"
|
||||
ng-click="toggleClosedStatus()"> less <i class="fa fa-angle-up"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-horizontal StandardOutDetails"
|
||||
role="form" id="job-status-form">
|
||||
<div class="form-group StandardOutDetails-detailRow">
|
||||
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-12
|
||||
StandardOutDetails-detailLabel">Status</label>
|
||||
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-12
|
||||
StandardOutDetails-detailContent">
|
||||
<i class="fa icon-job-{{ job.status }}"></i> {{ job.status }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div <div class="form-group StandardOutDetails-detailRow
|
||||
StandardOutDetails-detailRow--closable"
|
||||
ng-show="job.started">
|
||||
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-12
|
||||
StandardOutDetails-detailLabel">Timing</label>
|
||||
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-12
|
||||
StandardOutDetails-detailContent">
|
||||
<div ng-show="job.started" id="started-time">
|
||||
Started {{ job.started | date:'MM/dd/yy HH:mm:ss' }}
|
||||
</div>
|
||||
<div ng-show="job.finished" id="finished-time">
|
||||
Finished {{ job.finished | date:'MM/dd/yy HH:mm:ss' }}
|
||||
</div>
|
||||
<div ng-show="job.finished" id="elapsed-time">
|
||||
Elapsed {{ job.elapsed }} seconds
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div <div class="form-group StandardOutDetails-detailRow
|
||||
StandardOutDetails-detailRow--closable"
|
||||
ng-show="job.module_name">
|
||||
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-12
|
||||
StandardOutDetails-detailLabel">Module Name</label>
|
||||
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-12
|
||||
StandardOutDetails-detailContent">{{ job.module_name }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div <div class="form-group StandardOutDetails-detailRow
|
||||
StandardOutDetails-detailRow--closable"
|
||||
ng-show="job.module_args">
|
||||
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-12
|
||||
StandardOutDetails-detailLabel">Module Args</label>
|
||||
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-12
|
||||
StandardOutDetails-detailContent mono-space">{{ job.module_args }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div <div class="form-group StandardOutDetails-detailRow
|
||||
StandardOutDetails-detailRow--closable"
|
||||
ng-show="inventory_name">
|
||||
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-12
|
||||
StandardOutDetails-detailLabel">Inventory</label>
|
||||
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-12
|
||||
StandardOutDetails-detailContent">
|
||||
<a href="{{ inventory_url }}"
|
||||
aw-tool-tip="The inventory this command ran on."
|
||||
data-placement="top">{{ inventory_name }}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group StandardOutDetails-detailRow
|
||||
StandardOutDetails-detailRow--closable"
|
||||
ng-show="credential_name">
|
||||
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-12
|
||||
StandardOutDetails-detailLabel">Credential</label>
|
||||
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-12
|
||||
StandardOutDetails-detailContent">
|
||||
<a href="{{ credential_url }}"
|
||||
aw-tool-tip="The credential used to run this command."
|
||||
data-placement="top">{{ credential_name }}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group StandardOutDetails-detailRow
|
||||
StandardOutDetails-detailRow--closable"
|
||||
ng-show="created_by">
|
||||
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-12
|
||||
StandardOutDetails-detailContent">Launched By</label>
|
||||
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-9
|
||||
StandardOutDetails-detailContent">
|
||||
<a href="/#/users/{{ created_by.id }}"
|
||||
aw-tool-tip="The user who ran this command."
|
||||
data-placement="top">{{ created_by.username }}</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- since zero is a falsy value, you need ng-show such that
|
||||
the number is >= 0 -->
|
||||
<div class="form-group StandardOutDetails-detailRow
|
||||
StandardOutDetails-detailRow--closable"
|
||||
ng-show="forks >= 0">
|
||||
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-12
|
||||
StandardOutDetails-detailLabel">Forks</label>
|
||||
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-12
|
||||
StandardOutDetails-detailContent">{{ forks }}</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group StandardOutDetails-detailRow
|
||||
StandardOutDetails-detailRow--closable"
|
||||
ng-show="limit">
|
||||
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-12
|
||||
StandardOutDetails-detailLabel">Limit</label>
|
||||
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-12
|
||||
StandardOutDetails-detailContent">{{ limit }}</div>
|
||||
</div>
|
||||
|
||||
<!-- since zero is a falsy value, you need ng-show such that
|
||||
the number is >= 0 -->
|
||||
<div class="form-group StandardOutDetails-detailRow
|
||||
StandardOutDetails-detailRow--closable"
|
||||
ng-show="verbosity >= 0">
|
||||
<label class="col-lg-2 col-md-2 col-sm-2 col-xs-12
|
||||
StandardOutDetails-detailLabel">Verbosity</label>
|
||||
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-12
|
||||
StandardOutDetails-detailContent">{{ verbosity }}</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group StandardOutDetails-closedToggle">
|
||||
<a class="col-sm-12 StandardOutDetails-closedToggleLink"
|
||||
ng-show="isClosed" href="javascript:;"
|
||||
ng-click="toggleClosedStatus()"> more <i class="fa fa-angle-down"></i>
|
||||
</a>
|
||||
<a class="col-sm-12 StandardOutDetails-closedToggleLink"
|
||||
ng-show="!isClosed" href="javascript:;"
|
||||
ng-click="toggleClosedStatus()"> less <i class="fa fa-angle-up"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<div class="panel panel-default StandardOut-panel">
|
||||
<div class="panel-heading StandardOut-panelHeading">
|
||||
<h3 class="panel-title">Standard Output
|
||||
<a ng-href="/api/v1/ad_hoc_commands/{{ job.id }}/stdout?format=txt_download&token={{ token }}" class="btn btn-primary btn-xs DownloadStandardOut DownloadStandardOut--onStandardOutPage" id="download-stdout-button" type="button" aw-tool-tip="Download standard out as a .txt file" data-placement="top" ng-show="job.status === 'cancelled' || job.status === 'failed' || job.status === 'error' || job.status === 'successful'"><i class="fa fa-download DownloadStandardOut-icon DownloadStandardOut-icon--withText"></i>Download</a>
|
||||
</h3>
|
||||
</div>
|
||||
<div class="panel-body stdout-panel-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<div class="scroll-spinner" id="stdoutMoreRowsTop">
|
||||
<i class="fa fa-cog fa-spin"></i>
|
||||
</div>
|
||||
<div id="pre-container" class="body_background
|
||||
body_foreground pre mono-space"
|
||||
lr-infinite-scroll="stdOutScrollToTop"
|
||||
scroll-threshold="300" data-direction="up" time-threshold="500">
|
||||
<div id="pre-container-content"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="scroll-spinner" id="stdoutMoreRowsBottom">
|
||||
<i class="fa fa-cog fa-spin"></i>
|
||||
</div>
|
||||
<div class="panel-body stdout-panel-body StandardOut-panelBody">
|
||||
<div id="pre-container" class="body_background
|
||||
body_foreground pre mono-space StandardOut-preContainer"
|
||||
lr-infinite-scroll="stdOutScrollToTop"
|
||||
scroll-threshold="300" data-direction="up" time-threshold="500">
|
||||
<div id="pre-container-content" class="StandardOut-preContent"></div>
|
||||
</div>
|
||||
<div class="scroll-spinner" id="stdoutMoreRowsBottom">
|
||||
<i class="fa fa-cog fa-spin"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
return config;
|
||||
},
|
||||
responseError: function(rejection){
|
||||
if( !_.isEmpty(rejection.data.detail) && rejection.data.detail === "Maximum per-user sessions reached"){
|
||||
if( rejection.data && !_.isEmpty(rejection.data.detail) && rejection.data.detail === "Maximum per-user sessions reached"){
|
||||
$rootScope.sessionTimer.expireSession('session_limit');
|
||||
return $q.reject(rejection);
|
||||
}
|
||||
|
||||
@ -203,11 +203,11 @@ angular.module('Utilities', ['RestServices', 'Utilities', 'sanitizeFilter'])
|
||||
$rootScope.sessionTimer.expireSession('idle');
|
||||
}
|
||||
$location.url('/login');
|
||||
} else if (data.non_field_errors) {
|
||||
} else if (data && data.non_field_errors) {
|
||||
Alert('Error!', data.non_field_errors);
|
||||
} else if (data.detail) {
|
||||
} else if (data && data.detail) {
|
||||
Alert(defaultMsg.hdr, defaultMsg.msg + ' ' + data.detail);
|
||||
} else if (data.__all__) {
|
||||
} else if (data && data.__all__) {
|
||||
if (typeof data.__all__ === 'object' && Array.isArray(data.__all__)) {
|
||||
Alert('Error!', data.__all__[0]);
|
||||
}
|
||||
|
||||
47
awx/ui/client/src/standard-out/standardOut.block.less
Normal file
47
awx/ui/client/src/standard-out/standardOut.block.less
Normal file
@ -0,0 +1,47 @@
|
||||
/** @define StandardOut */
|
||||
|
||||
.StandardOut {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.StandardOut-header {
|
||||
flex: initial;
|
||||
}
|
||||
|
||||
.StandardOut-breadcrumbs {
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
.StandardOut-form {
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
.StandardOut-panel {
|
||||
flex: 1 0 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: -41px;
|
||||
}
|
||||
|
||||
.StandardOut-panelHeading {
|
||||
flex: initial;
|
||||
}
|
||||
|
||||
.StandardOut-panelBody {
|
||||
flex: 1 0 auto;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.StandardOut-preContainer {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.StandardOut-preContent {
|
||||
position: absolute;
|
||||
}
|
||||
@ -5,6 +5,12 @@ export default
|
||||
return _.pluck(nonEmptyResults, 'versions[0]');
|
||||
}
|
||||
|
||||
// if the version that will be displayed on the left is before the
|
||||
// version that will be displayed on the right, flip them
|
||||
if (nonEmptyResults[0].versions[0].timestamp > nonEmptyResults[1].versions[0].timestamp) {
|
||||
nonEmptyResults = nonEmptyResults.reverse();
|
||||
}
|
||||
|
||||
var firstTimestamp = nonEmptyResults[0].versions[0].timestamp;
|
||||
|
||||
var hostIdsWithDupes =
|
||||
|
||||
@ -4,8 +4,10 @@ function resolveEmptyVersions(service, _, candidate, previousResult) {
|
||||
|
||||
candidate = _.merge({}, candidate);
|
||||
|
||||
if (_.isEmpty(candidate.versions)) {
|
||||
var originalStartDate = candidate.dateRange.from.clone();
|
||||
// theoretically, returning no versions, but also returning only a single version for _a particular date_ acts as an empty version problem. If there is only one version returned, you'll need to check previous dates as well.
|
||||
if (_.isEmpty(candidate.versions) || candidate.versions.length === 1) {
|
||||
// this marks the end of the date put in the datepicker. this needs to be the end, rather than the beginning of the date, because you may have returned one valid version on the date the datepicker had in it.
|
||||
var originalStartDate = candidate.dateRange.to.clone();
|
||||
|
||||
if (!_.isUndefined(previousResult)) {
|
||||
candidate.dateRange.from = moment(previousResult.versions[0].timestamp);
|
||||
|
||||
@ -15,7 +15,8 @@
|
||||
<span class="u-unbold">on</span>
|
||||
</span>
|
||||
<span class="FactDataTableHeading-host" ng-if="!leftDataNoScans">{{leftHostname}}</span>
|
||||
<span class="FactDataTableHeading-date">{{leftScanDate|longDate}}</span>
|
||||
<span class="FactDataTableHeading-date" ng-if="!singleResultView">{{leftScanDate|longDate}}</span>
|
||||
<span class="FactDataTableHeading-date" ng-if="singleResultView">{{rightScanDate|longDate}}</span>
|
||||
</h3>
|
||||
<h3 class="FactDataTable-column FactDataTableHeading" ng-if="!singleResultView">
|
||||
<span ng-if="rightDataNoScans">No scans for {{rightHostname}} on</span>
|
||||
|
||||
@ -91,7 +91,7 @@ function controller($rootScope,
|
||||
if (_.isEmpty(data[0]) && _.isEmpty(data[1])) {
|
||||
return _.reject({
|
||||
name: 'NoScanData',
|
||||
message: 'There was insufficient scan data for both of the dates you selected. Please try selecting a different date or module.',
|
||||
message: 'There was insufficient scan data for the date you selected. Please try selecting a different date or module.',
|
||||
dateValues:
|
||||
{ leftDate: $scope.leftDate.clone(),
|
||||
rightDate: $scope.rightDate.clone()
|
||||
|
||||
@ -58,7 +58,7 @@
|
||||
|
||||
<!-- Password Dialog -->
|
||||
<div id="password-modal" style="display: none;"></div>
|
||||
<div id="idle-modal" style="display:none">Your session will expire in 1 minute, would you like to continue?</div>
|
||||
<div id="idle-modal" style="display:none">Your session will expire in <span id="remaining_seconds"></span> seconds, would you like to continue?</div>
|
||||
|
||||
<!-- Generic Form dialog -->
|
||||
<div id="form-modal" class="modal fade">
|
||||
|
||||
@ -18,4 +18,4 @@ exclude=.tox,awx/lib/site-packages,awx/plugins/inventory/ec2.py,awx/plugins/inve
|
||||
|
||||
[flake8]
|
||||
ignore=E201,E203,E221,E225,E231,E241,E251,E261,E265,E302,E303,E501,W291,W391,W293,E731
|
||||
exclude=.tox,awx/lib/site-packages,awx/plugins/inventory/ec2.py,awx/plugins/inventory/gce.py,awx/plugins/inventory/vmware.py,awx/plugins/inventory/windows_azure.py,awx/plugins/inventory/openstack.py,awx/ui,awx/api/urls.py,awx/main/migrations,awx/main/tests/data,node_modules/,awx/projects/,tools/docker
|
||||
exclude=.tox,awx/lib/site-packages,awx/plugins/inventory/ec2.py,awx/plugins/inventory/gce.py,awx/plugins/inventory/vmware.py,awx/plugins/inventory/windows_azure.py,awx/plugins/inventory/openstack.py,awx/plugins/inventory/rax.py,awx/ui,awx/api/urls.py,awx/main/migrations,awx/main/tests/data,node_modules/,awx/projects/,tools/docker
|
||||
|
||||
@ -20,4 +20,11 @@ redis:
|
||||
mongo:
|
||||
image: mongo:3.0
|
||||
# ports:
|
||||
# - 27017:27017
|
||||
# - 27017:27017
|
||||
dockerui:
|
||||
image: dockerui/dockerui
|
||||
ports:
|
||||
- "9000:9000"
|
||||
privileged: true
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
|
||||
@ -31,26 +31,35 @@
|
||||
with_items: ami_info.results
|
||||
|
||||
- name: Copy AMI to desired regions
|
||||
ec2_ami_copy:
|
||||
source_region: '{{ src_region }}'
|
||||
region: '{{ item }}'
|
||||
source_image_id: '{{ ami_info.results[0].ami_id }}'
|
||||
name: '{{ ami_info.results[0].name }}'
|
||||
description: '{{ ami_info.results[0].description }}'
|
||||
tags: '{{ ami_info.results[0].tags }}'
|
||||
wait: true
|
||||
command: 'ec2-copy-image --source-region {{ src_region }} --source-ami-id {{ src_ami_id }} --region {{ item }} --client-token {{ src_ami_id }}-{{ item }}'
|
||||
with_items: dst_regions
|
||||
register: ami_copy
|
||||
|
||||
- name: Make image publicly available
|
||||
command: 'ec2-modify-image-attribute {{ item.image_id }} --launch-permission -a all'
|
||||
with_items: ami_copy.results
|
||||
# ec2_ami_copy:
|
||||
# source_region: '{{ src_region }}'
|
||||
# region: '{{ item }}'
|
||||
# source_image_id: '{{ ami_info.results[0].ami_id }}'
|
||||
# name: '{{ ami_info.results[0].name }}'
|
||||
# description: '{{ ami_info.results[0].description }}'
|
||||
# tags: '{{ ami_info.results[0].tags }}'
|
||||
# wait: true
|
||||
# with_items: dst_regions
|
||||
# register: ami_copy
|
||||
|
||||
- debug:
|
||||
var: ami_copy.results
|
||||
- name: Wait for AMI's to become available
|
||||
command: 'ec2-describe-images --region {{ item.item }} --filter state=available {{ item.stdout[-12:] }}'
|
||||
until: ami_available.stdout.find("available") != -1
|
||||
retries: 10
|
||||
delay: 120
|
||||
with_items: ami_copy.results
|
||||
register: ami_available
|
||||
|
||||
- name: Make image publicly available
|
||||
command: 'ec2-modify-image-attribute --region {{ item.item }} {{ item.stdout[-12:] }} --launch-permission -a all'
|
||||
with_items: ami_copy.results
|
||||
|
||||
- name: Display AMI launch URL
|
||||
debug:
|
||||
msg: 'https://console.aws.amazon.com/ec2/home?region={{ item.item }}#launchAmi={{ item.image_id }}'
|
||||
msg: 'https://console.aws.amazon.com/ec2/home?region={{ item.item }}#launchAmi={{ item.stdout[-12:] }}'
|
||||
with_items: ami_copy.results
|
||||
when: ami_copy is defined
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user