mirror of
https://github.com/ansible/awx.git
synced 2026-01-22 15:08:03 -03:30
Merge branch 'master' into expunge-zeromq-unstable
This commit is contained in:
commit
f000e71371
1
.gitignore
vendored
1
.gitignore
vendored
@ -52,6 +52,7 @@ tools/vagrant/local.yml
|
||||
# Setup
|
||||
setup/tower_setup_conf.yml
|
||||
setup/setup.log
|
||||
setup/inventory
|
||||
|
||||
# Other
|
||||
.tower_cycle
|
||||
|
||||
@ -109,6 +109,8 @@ class ApiV1RootView(APIView):
|
||||
data['hosts'] = reverse('api:host_list')
|
||||
data['job_templates'] = reverse('api:job_template_list')
|
||||
data['jobs'] = reverse('api:job_list')
|
||||
data['system_job_templates'] = reverse('api:system_job_template_list')
|
||||
data['system_jobs'] = reverse('api:system_job_list')
|
||||
data['schedules'] = reverse('api:schedule_list')
|
||||
data['unified_job_templates'] = reverse('api:unified_job_template_list')
|
||||
data['unified_jobs'] = reverse('api:unified_job_list')
|
||||
@ -1720,6 +1722,11 @@ class SystemJobTemplateList(ListAPIView):
|
||||
model = SystemJobTemplate
|
||||
serializer_class = SystemJobTemplateSerializer
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if not request.user.is_superuser:
|
||||
return Response(status=status.HTTP_404_NOT_FOUND)
|
||||
return super(SystemJobTemplateList, self).get(request, *args, **kwargs)
|
||||
|
||||
class SystemJobTemplateDetail(RetrieveAPIView):
|
||||
|
||||
model = SystemJobTemplate
|
||||
@ -1738,7 +1745,7 @@ class SystemJobTemplateLaunch(GenericAPIView):
|
||||
raise PermissionDenied()
|
||||
new_job = obj.create_unified_job()
|
||||
result = new_job.signal_start()
|
||||
data = dict(job=new_job.id)
|
||||
data = dict(system_job=new_job.id)
|
||||
return Response(data, status=status.HTTP_202_ACCEPTED)
|
||||
|
||||
class SystemJobTemplateSchedulesList(SubListCreateAPIView):
|
||||
@ -2174,6 +2181,12 @@ class SystemJobList(ListCreateAPIView):
|
||||
model = SystemJob
|
||||
serializer_class = SystemJobListSerializer
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
if not request.user.is_superuser:
|
||||
return Response(status=status.HTTP_404_NOT_FOUND)
|
||||
return super(SystemJobList, self).get(request, *args, **kwargs)
|
||||
|
||||
|
||||
class SystemJobDetail(RetrieveAPIView):
|
||||
|
||||
model = SystemJob
|
||||
|
||||
@ -980,6 +980,8 @@ class JobAccess(BaseAccess):
|
||||
def can_add(self, data):
|
||||
if not data or '_method' in data: # So the browseable API will work?
|
||||
return True
|
||||
if not self.user.is_superuser:
|
||||
return False
|
||||
|
||||
reader = TaskSerializer()
|
||||
validation_info = reader.from_file()
|
||||
@ -995,8 +997,6 @@ class JobAccess(BaseAccess):
|
||||
if validation_info.get('free_instances', 0) < 0:
|
||||
raise PermissionDenied("Host Count exceeds available instances")
|
||||
|
||||
if self.user.is_superuser:
|
||||
return True
|
||||
add_data = dict(data.items())
|
||||
|
||||
# If a job template is provided, the user should have read access to it.
|
||||
@ -1012,9 +1012,6 @@ class JobAccess(BaseAccess):
|
||||
add_data.setdefault('credential', job_template.credential.pk)
|
||||
else:
|
||||
job_template = None
|
||||
# Only admins can create jobs without job templates
|
||||
if not self.user.is_superuser:
|
||||
return False
|
||||
|
||||
# Check that the user would be able to add a job template with the
|
||||
# same data.
|
||||
|
||||
@ -8,6 +8,7 @@ import logging
|
||||
import json
|
||||
import signal
|
||||
import time
|
||||
import urllib
|
||||
from optparse import make_option
|
||||
from threading import Thread
|
||||
|
||||
@ -31,23 +32,71 @@ from socketio import socketio_manage
|
||||
from socketio.server import SocketIOServer
|
||||
from socketio.namespace import BaseNamespace
|
||||
|
||||
class TestNamespace(BaseNamespace):
|
||||
class TowerBaseNamespace(BaseNamespace):
|
||||
|
||||
def get_allowed_methods(self):
|
||||
return []
|
||||
|
||||
def get_initial_acl(self):
|
||||
print self
|
||||
if self.valid_user() is not None:
|
||||
return set(['recv_connect'] + self.get_allowed_methods())
|
||||
return set()
|
||||
|
||||
def valid_user(self):
|
||||
if 'HTTP_COOKIE' not in self.environ:
|
||||
return False
|
||||
else:
|
||||
try:
|
||||
all_keys = [e.strip() for e in self.environ['HTTP_COOKIE'].split(";")]
|
||||
for each_key in all_keys:
|
||||
k, v = each_key.split("=")
|
||||
if k == "token":
|
||||
token_actual = urllib.unquote_plus(v).decode().replace("\"","")
|
||||
auth_token = AuthToken.objects.filter(key=token_actual)
|
||||
if not auth_token.exists():
|
||||
return False
|
||||
auth_token = auth_token[0]
|
||||
if not auth_token.expired:
|
||||
return auth_token.user
|
||||
else:
|
||||
return False
|
||||
except Exception, e:
|
||||
return False
|
||||
|
||||
class TestNamespace(TowerBaseNamespace):
|
||||
|
||||
def recv_connect(self):
|
||||
print("Received client connect for test namespace from %s" % str(self.environ['REMOTE_ADDR']))
|
||||
self.emit('test', "If you see this then you are connected to the test socket endpoint")
|
||||
|
||||
class JobNamespace(BaseNamespace):
|
||||
class JobNamespace(TowerBaseNamespace):
|
||||
|
||||
def get_allowed_methods(self):
|
||||
return ['summary_complete', 'status_changed']
|
||||
|
||||
def recv_connect(self):
|
||||
print("Received client connect for job namespace from %s" % str(self.environ['REMOTE_ADDR']))
|
||||
|
||||
class JobEventNamespace(BaseNamespace):
|
||||
class JobEventNamespace(TowerBaseNamespace):
|
||||
|
||||
def get_initial_acl(self):
|
||||
valid_user = self.valid_user()
|
||||
if valid_user is None or valid_user is False:
|
||||
return set()
|
||||
else:
|
||||
user_jobs = get_user_queryset(valid_user, Job).filter(finished__isnull=True)
|
||||
visible_jobs = set(['recv_connect'] + ["job_events-%s" % str(j.id) for j in user_jobs])
|
||||
print("Visible jobs: " + str(visible_jobs))
|
||||
return visible_jobs
|
||||
|
||||
def recv_connect(self):
|
||||
print("Received client connect for job event namespace from %s" % str(self.environ['REMOTE_ADDR']))
|
||||
|
||||
class ScheduleNamespace(BaseNamespace):
|
||||
class ScheduleNamespace(TowerBaseNamespace):
|
||||
|
||||
def get_allowed_methods(self):
|
||||
return ["schedule_changed"]
|
||||
|
||||
def recv_connect(self):
|
||||
print("Received client connect for schedule namespace from %s" % str(self.environ['REMOTE_ADDR']))
|
||||
|
||||
494
awx/main/migrations/0059_v210_changes.py
Normal file
494
awx/main/migrations/0059_v210_changes.py
Normal file
@ -0,0 +1,494 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from south.utils import datetime_utils as datetime
|
||||
from south.db import db
|
||||
from south.v2 import DataMigration
|
||||
from django.db import models
|
||||
from django.utils.timezone import now
|
||||
from awx.main.models import *
|
||||
|
||||
class Migration(DataMigration):
|
||||
|
||||
def forwards(self, orm):
|
||||
SystemJobTemplate(name='Delete Old Jobs',
|
||||
description="Run a job to delete jobs that are older than a given number of days",
|
||||
job_type="cleanup_jobs",
|
||||
created=now(),
|
||||
modified=now()).save()
|
||||
SystemJobTemplate(name='Cleanup Deleted Data',
|
||||
description="Run a job to cleanup any deleted objects that are older than a given number of days",
|
||||
job_type="cleanup_deleted",
|
||||
created=now(),
|
||||
modified=now()).save()
|
||||
SystemJobTemplate(name='Cleanup Activity Stream',
|
||||
description="Run a job to purge activity stream data that's older than a given number of days",
|
||||
job_type="cleanup_activitystream",
|
||||
created=now(),
|
||||
modified=now()).save()
|
||||
|
||||
def backwards(self, orm):
|
||||
orm.SystemJobTemplate.objects.all().delete()
|
||||
|
||||
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']"}),
|
||||
'changes': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||
'credential': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['main.Credential']", '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.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'}),
|
||||
'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'}),
|
||||
'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'}),
|
||||
'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'}),
|
||||
'su_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'su_username': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'sudo_password': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1024', 'blank': 'True'}),
|
||||
'sudo_username': ('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',)", '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', [], {'unique': 'True', 'max_length': '512'}),
|
||||
'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'}),
|
||||
u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||
'ip_address': ('django.db.models.fields.GenericIPAddressField', [], {'max_length': '39'}),
|
||||
'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']"}),
|
||||
'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'}),
|
||||
'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']},
|
||||
'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', [], {'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'}),
|
||||
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobs'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Project']"}),
|
||||
'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'}),
|
||||
'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', [], {'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'}),
|
||||
'project': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'jobtemplates'", 'null': 'True', 'on_delete': 'models.SET_NULL', 'to': "orm['main.Project']"}),
|
||||
'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']"}),
|
||||
'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'}),
|
||||
'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']
|
||||
symmetrical = True
|
||||
@ -957,7 +957,7 @@ class RunInventoryUpdate(BaseTask):
|
||||
ec2_opts['cache_path'] = cache_path
|
||||
ec2_opts.setdefault('cache_max_age', '300')
|
||||
for k,v in ec2_opts.items():
|
||||
cp.set(section, k, str(v))
|
||||
cp.set(section, k, unicode(v))
|
||||
# Build pyrax creds INI for rax inventory script.
|
||||
elif inventory_update.source == 'rax':
|
||||
section = 'rackspace_cloud'
|
||||
@ -967,6 +967,15 @@ class RunInventoryUpdate(BaseTask):
|
||||
cp.set(section, 'username', credential.username)
|
||||
cp.set(section, 'api_key', decrypt_field(credential,
|
||||
'password'))
|
||||
# Allow custom options to vmware inventory script.
|
||||
elif inventory_update.source == 'vmware':
|
||||
section = 'defaults'
|
||||
cp.add_section(section)
|
||||
vmware_opts = dict(inventory_update.source_vars_dict.items())
|
||||
vmware_opts.setdefault('guests_only', 'True')
|
||||
for k,v in vmware_opts.items():
|
||||
cp.set(section, k, unicode(v))
|
||||
|
||||
# Return INI content.
|
||||
if cp.sections():
|
||||
f = cStringIO.StringIO()
|
||||
@ -1027,6 +1036,7 @@ class RunInventoryUpdate(BaseTask):
|
||||
# complain about not being able to determine its version number.
|
||||
env['PBR_VERSION'] = '0.5.21'
|
||||
elif inventory_update.source == 'vmware':
|
||||
env['VMWARE_INI'] = kwargs.get('private_data_file', '')
|
||||
env['VMWARE_HOST'] = passwords.get('source_host', '')
|
||||
env['VMWARE_USER'] = passwords.get('source_username', '')
|
||||
env['VMWARE_PASSWORD'] = passwords.get('source_password', '')
|
||||
@ -1042,8 +1052,8 @@ class RunInventoryUpdate(BaseTask):
|
||||
pass
|
||||
elif inventory_update.source == 'custom':
|
||||
for env_k in inventory_update.source_vars_dict:
|
||||
if env_k not in os.environ:
|
||||
env[env_k] = unicode(inventory_update.source_vars_dict[env_k])
|
||||
if str(env_k) not in os.environ:
|
||||
env[str(env_k)] = unicode(inventory_update.source_vars_dict[env_k])
|
||||
return env
|
||||
|
||||
def build_args(self, inventory_update, **kwargs):
|
||||
@ -1146,6 +1156,13 @@ class RunSystemJob(BaseTask):
|
||||
json_vars = json.loads(system_job.extra_vars)
|
||||
if 'days' in json_vars:
|
||||
args.extend(['--days', str(json_vars['days'])])
|
||||
if system_job.job_type == 'cleanup_jobs':
|
||||
if 'jobs' in json_vars and json_vars['jobs']:
|
||||
args.extend(['--jobs'])
|
||||
if 'project_updates' in json_vars and json_vars['project_updates']:
|
||||
args.extend(['--project-updates'])
|
||||
if 'inventory_updates' in json_vars and json_vars['inventory_updates']:
|
||||
args.extend(['--inventory-updates'])
|
||||
except Exception, e:
|
||||
pass
|
||||
print args
|
||||
|
||||
@ -1562,6 +1562,62 @@ class InventoryUpdatesTest(BaseTransactionTest):
|
||||
# its own child).
|
||||
self.assertTrue(self.group in self.inventory.root_groups)
|
||||
|
||||
def test_update_from_vmware(self):
|
||||
source_host = getattr(settings, 'TEST_VMWARE_HOST', '')
|
||||
source_username = getattr(settings, 'TEST_VMWARE_USER', '')
|
||||
source_password = getattr(settings, 'TEST_VMWARE_PASSWORD', '')
|
||||
if not all([source_host, source_username, source_password]):
|
||||
self.skipTest('no test vmware credentials defined!')
|
||||
self.create_test_license_file()
|
||||
credential = Credential.objects.create(kind='vmware',
|
||||
user=self.super_django_user,
|
||||
username=source_username,
|
||||
password=source_password,
|
||||
host=source_host)
|
||||
inventory_source = self.update_inventory_source(self.group,
|
||||
source='vmware', credential=credential)
|
||||
# Check first without instance_id set (to import by name only).
|
||||
with self.settings(VMWARE_INSTANCE_ID_VAR=''):
|
||||
self.check_inventory_source(inventory_source)
|
||||
# Rename hosts and verify the import picks up the instance_id present
|
||||
# in host variables.
|
||||
for host in self.inventory.hosts.all():
|
||||
self.assertFalse(host.instance_id, host.instance_id)
|
||||
if host.enabled:
|
||||
self.assertTrue(host.variables_dict.get('ansible_ssh_host', ''))
|
||||
# Test a field that should be present for host systems, not VMs.
|
||||
self.assertFalse(host.variables_dict.get('vmware_product_name', ''))
|
||||
host.name = 'updated-%s' % host.name
|
||||
host.save()
|
||||
old_host_pks = set(self.inventory.hosts.values_list('pk', flat=True))
|
||||
self.check_inventory_source(inventory_source, initial=False)
|
||||
new_host_pks = set(self.inventory.hosts.values_list('pk', flat=True))
|
||||
self.assertEqual(old_host_pks, new_host_pks)
|
||||
# Manually disable all hosts, verify a new update re-enables them.
|
||||
# Also change the host name, and verify it is not deleted, but instead
|
||||
# updated because the instance ID matches.
|
||||
enabled_host_pks = set(self.inventory.hosts.filter(enabled=True).values_list('pk', flat=True))
|
||||
for host in self.inventory.hosts.all():
|
||||
host.enabled = False
|
||||
host.name = 'changed-%s' % host.name
|
||||
host.save()
|
||||
old_host_pks = set(self.inventory.hosts.values_list('pk', flat=True))
|
||||
self.check_inventory_source(inventory_source, initial=False, enabled_host_pks=enabled_host_pks)
|
||||
new_host_pks = set(self.inventory.hosts.values_list('pk', flat=True))
|
||||
self.assertEqual(old_host_pks, new_host_pks)
|
||||
# Update again and include host systems in addition to guests.
|
||||
inventory_source.source_vars = '---\n\nguests_only: false\n'
|
||||
inventory_source.save()
|
||||
old_host_pks = set(self.inventory.hosts.values_list('pk', flat=True))
|
||||
self.check_inventory_source(inventory_source, initial=False)
|
||||
new_host_pks = set(self.inventory.hosts.values_list('pk', flat=True))
|
||||
self.assertTrue(new_host_pks > old_host_pks)
|
||||
for host in self.inventory.hosts.filter(pk__in=(new_host_pks - old_host_pks)):
|
||||
if host.enabled:
|
||||
self.assertTrue(host.variables_dict.get('ansible_ssh_host', ''))
|
||||
# Test a field only present for host systems.
|
||||
self.assertTrue(host.variables_dict.get('vmware_product_name', ''))
|
||||
|
||||
def test_update_from_custom_script(self):
|
||||
# Create the inventory script
|
||||
self.create_test_license_file()
|
||||
|
||||
@ -1,232 +1,414 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
VMWARE external inventory script
|
||||
=================================
|
||||
VMware Inventory Script
|
||||
=======================
|
||||
|
||||
shamelessly copied from existing inventory scripts.
|
||||
Retrieve information about virtual machines from a vCenter server or
|
||||
standalone ESX host. When `group_by=false` (in the INI file), host systems
|
||||
are also returned in addition to VMs.
|
||||
|
||||
This script and it's ini can be used more than once,
|
||||
This script will attempt to read configuration from an INI file with the same
|
||||
base filename if present, or `vmware.ini` if not. It is possible to create
|
||||
symlinks to the inventory script to support multiple configurations, e.g.:
|
||||
|
||||
i.e vmware.py/vmware_colo.ini vmware_idf.py/vmware_idf.ini
|
||||
(script can be link)
|
||||
* `vmware.py` (this script)
|
||||
* `vmware.ini` (default configuration, will be read by `vmware.py`)
|
||||
* `vmware_test.py` (symlink to `vmware.py`)
|
||||
* `vmware_test.ini` (test configuration, will be read by `vmware_test.py`)
|
||||
* `vmware_other.py` (symlink to `vmware.py`, will read `vmware.ini` since no
|
||||
`vmware_other.ini` exists)
|
||||
|
||||
so if you don't have clustered vcenter but multiple esx machines or
|
||||
just diff clusters you can have a inventory per each and automatically
|
||||
group hosts based on file name or specify a group in the ini.
|
||||
The path to an INI file may also be specified via the `VMWARE_INI` environment
|
||||
variable, in which case the filename matching rules above will not apply.
|
||||
|
||||
Host and authentication parameters may be specified via the `VMWARE_HOST`,
|
||||
`VMWARE_USER` and `VMWARE_PASSWORD` environment variables; these options will
|
||||
take precedence over options present in the INI file. An INI file is not
|
||||
required if these options are specified using environment variables.
|
||||
'''
|
||||
|
||||
import collections
|
||||
import json
|
||||
import logging
|
||||
import optparse
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import ConfigParser
|
||||
from psphere.client import Client
|
||||
from psphere.managedobjects import HostSystem
|
||||
|
||||
# Disable logging message trigged by pSphere/suds.
|
||||
try:
|
||||
import json
|
||||
from logging import NullHandler
|
||||
except ImportError:
|
||||
import simplejson as json
|
||||
from logging import Handler
|
||||
class NullHandler(Handler):
|
||||
def emit(self, record):
|
||||
pass
|
||||
logging.getLogger('psphere').addHandler(NullHandler())
|
||||
logging.getLogger('suds').addHandler(NullHandler())
|
||||
|
||||
from psphere.client import Client
|
||||
from psphere.errors import ObjectNotFoundError
|
||||
from psphere.managedobjects import HostSystem, VirtualMachine, ManagedObject, Network
|
||||
from suds.sudsobject import Object as SudsObject
|
||||
|
||||
|
||||
def save_cache(cache_item, data, config):
|
||||
''' saves item to cache '''
|
||||
class VMwareInventory(object):
|
||||
|
||||
def __init__(self, guests_only=None):
|
||||
self.config = ConfigParser.SafeConfigParser()
|
||||
if os.environ.get('VMWARE_INI', ''):
|
||||
config_files = [os.environ['VMWARE_INI']]
|
||||
else:
|
||||
config_files = [os.path.abspath(sys.argv[0]).rstrip('.py') + '.ini', 'vmware.ini']
|
||||
for config_file in config_files:
|
||||
if os.path.exists(config_file):
|
||||
self.config.read(config_file)
|
||||
break
|
||||
|
||||
# Sanity check: Is caching enabled? If not, don't cache.
|
||||
if not config.has_option('defaults', 'cache_dir'):
|
||||
return
|
||||
# Retrieve only guest VMs, or include host systems?
|
||||
if guests_only is not None:
|
||||
self.guests_only = guests_only
|
||||
elif self.config.has_option('defaults', 'guests_only'):
|
||||
self.guests_only = self.config.getboolean('defaults', 'guests_only')
|
||||
else:
|
||||
self.guests_only = True
|
||||
|
||||
dpath = config.get('defaults', 'cache_dir')
|
||||
try:
|
||||
cache = open('/'.join([dpath,cache_item]), 'w')
|
||||
cache.write(json.dumps(data))
|
||||
cache.close()
|
||||
except IOError, e:
|
||||
pass # not really sure what to do here
|
||||
# Read authentication information from VMware environment variables
|
||||
# (if set), otherwise from INI file.
|
||||
auth_host = os.environ.get('VMWARE_HOST')
|
||||
if not auth_host and self.config.has_option('auth', 'host'):
|
||||
auth_host = self.config.get('auth', 'host')
|
||||
auth_user = os.environ.get('VMWARE_USER')
|
||||
if not auth_user and self.config.has_option('auth', 'user'):
|
||||
auth_user = self.config.get('auth', 'user')
|
||||
auth_password = os.environ.get('VMWARE_PASSWORD')
|
||||
if not auth_password and self.config.has_option('auth', 'password'):
|
||||
auth_password = self.config.get('auth', 'password')
|
||||
|
||||
# Create the VMware client connection.
|
||||
self.client = Client(auth_host, auth_user, auth_password)
|
||||
|
||||
def get_cache(cache_item, config):
|
||||
''' returns cached item '''
|
||||
def _put_cache(self, name, value):
|
||||
'''
|
||||
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')
|
||||
if not os.path.exists(cache_dir):
|
||||
os.makedirs(cache_dir)
|
||||
cache_file = os.path.join(cache_dir, name)
|
||||
with open(cache_file, 'w') as cache:
|
||||
json.dump(value, cache)
|
||||
|
||||
# Sanity check: Is caching enabled? If not, return None.
|
||||
if not config.has_option('defaults', 'cache_dir'):
|
||||
return
|
||||
def _get_cache(self, name, default=None):
|
||||
'''
|
||||
Retrieves the value from cache for the given name.
|
||||
'''
|
||||
if self.config.has_option('defaults', 'cache_dir'):
|
||||
cache_dir = self.config.get('defaults', 'cache_dir')
|
||||
cache_file = os.path.join(cache_dir, name)
|
||||
if os.path.exists(cache_file):
|
||||
if self.config.has_option('defaults', 'cache_max_age'):
|
||||
cache_max_age = self.config.getint('defaults', 'cache_max_age')
|
||||
else:
|
||||
cache_max_age = 0
|
||||
cache_stat = os.stat(cache_file)
|
||||
if (cache_stat.st_mtime + cache_max_age) < time.time():
|
||||
with open(cache_file) as cache:
|
||||
return json.load(cache)
|
||||
return default
|
||||
|
||||
dpath = config.get('defaults', 'cache_dir')
|
||||
inv = {}
|
||||
try:
|
||||
cache = open('/'.join([dpath,cache_item]), 'r')
|
||||
inv = json.loads(cache.read())
|
||||
cache.close()
|
||||
except IOError, e:
|
||||
pass # not really sure what to do here
|
||||
def _flatten_dict(self, d, parent_key='', sep='_'):
|
||||
'''
|
||||
Flatten nested dicts by combining keys with a separator. Lists with
|
||||
only string items are included as is; any other lists are discarded.
|
||||
'''
|
||||
items = []
|
||||
for k, v in d.items():
|
||||
if k.startswith('_'):
|
||||
continue
|
||||
new_key = parent_key + sep + k if parent_key else k
|
||||
if isinstance(v, collections.MutableMapping):
|
||||
items.extend(self._flatten_dict(v, new_key, sep).items())
|
||||
elif isinstance(v, (list, tuple)):
|
||||
if all([isinstance(x, basestring) for x in v]):
|
||||
items.append((new_key, v))
|
||||
else:
|
||||
items.append((new_key, v))
|
||||
return dict(items)
|
||||
|
||||
return inv
|
||||
|
||||
def cache_available(cache_item, config):
|
||||
''' checks if we have a 'fresh' cache available for item requested '''
|
||||
|
||||
if config.has_option('defaults', 'cache_dir'):
|
||||
dpath = config.get('defaults', 'cache_dir')
|
||||
def _get_obj_info(self, obj, depth=99, seen=None):
|
||||
'''
|
||||
Recursively build a data structure for the given pSphere object (depth
|
||||
only applies to ManagedObject instances).
|
||||
'''
|
||||
seen = seen or set()
|
||||
if isinstance(obj, ManagedObject):
|
||||
try:
|
||||
obj_unicode = unicode(getattr(obj, 'name'))
|
||||
except AttributeError:
|
||||
obj_unicode = ()
|
||||
if obj in seen:
|
||||
return obj_unicode
|
||||
seen.add(obj)
|
||||
if depth <= 0:
|
||||
return obj_unicode
|
||||
d = {}
|
||||
for attr in dir(obj):
|
||||
if attr.startswith('_'):
|
||||
continue
|
||||
try:
|
||||
val = getattr(obj, attr)
|
||||
obj_info = self._get_obj_info(val, depth - 1, seen)
|
||||
if obj_info != ():
|
||||
d[attr] = obj_info
|
||||
except Exception, e:
|
||||
pass
|
||||
return d
|
||||
elif isinstance(obj, SudsObject):
|
||||
d = {}
|
||||
for key, val in iter(obj):
|
||||
obj_info = self._get_obj_info(val, depth, seen)
|
||||
if obj_info != ():
|
||||
d[key] = obj_info
|
||||
return d
|
||||
elif isinstance(obj, (list, tuple)):
|
||||
l = []
|
||||
for val in iter(obj):
|
||||
obj_info = self._get_obj_info(val, depth, seen)
|
||||
if obj_info != ():
|
||||
l.append(obj_info)
|
||||
return l
|
||||
elif isinstance(obj, (type(None), bool, int, long, float, basestring)):
|
||||
return obj
|
||||
else:
|
||||
return ()
|
||||
|
||||
def _get_host_info(self, host, prefix='vmware'):
|
||||
'''
|
||||
Return a flattened dict with info about the given host system.
|
||||
'''
|
||||
host_info = {
|
||||
'name': host.name,
|
||||
'tag': host.tag,
|
||||
'datastores': self._get_obj_info(host.datastore, depth=0),
|
||||
'networks': self._get_obj_info(host.network, depth=0),
|
||||
'vms': self._get_obj_info(host.vm, depth=0),
|
||||
}
|
||||
for k, v in self._get_obj_info(host.summary, depth=0).items():
|
||||
if isinstance(v, collections.MutableMapping):
|
||||
for k2, v2 in v.items():
|
||||
host_info[k2] = v2
|
||||
elif k != 'host':
|
||||
host_info[k] = v
|
||||
try:
|
||||
existing = os.stat( '/'.join([dpath,cache_item]))
|
||||
except:
|
||||
# cache doesn't exist or isn't accessible
|
||||
return False
|
||||
host_info['ipAddress'] = host.config.network.vnic[0].spec.ip.ipAddress
|
||||
except Exception, e:
|
||||
print >> sys.stderr, e
|
||||
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]
|
||||
return host_info
|
||||
|
||||
if config.has_option('defaults', 'cache_max_age'):
|
||||
maxage = config.get('defaults', 'cache_max_age')
|
||||
def _get_vm_info(self, vm, prefix='vmware'):
|
||||
'''
|
||||
Return a flattened dict with info about the given virtual machine.
|
||||
'''
|
||||
vm_info = {
|
||||
'name': vm.name,
|
||||
'tag': vm.tag,
|
||||
'datastores': self._get_obj_info(vm.datastore, depth=0),
|
||||
'networks': self._get_obj_info(vm.network, depth=0),
|
||||
'resourcePool': self._get_obj_info(vm.resourcePool, depth=0),
|
||||
'guestState': vm.guest.guestState,
|
||||
}
|
||||
for k, v in self._get_obj_info(vm.summary, depth=0).items():
|
||||
if isinstance(v, collections.MutableMapping):
|
||||
for k2, v2 in v.items():
|
||||
if k2 == 'host':
|
||||
k2 = 'hostSystem'
|
||||
vm_info[k2] = v2
|
||||
elif k != 'vm':
|
||||
vm_info[k] = v
|
||||
vm_info = self._flatten_dict(vm_info, prefix)
|
||||
if ('%s_ipAddress' % prefix) in vm_info:
|
||||
vm_info['ansible_ssh_host'] = vm_info['%s_ipAddress' % prefix]
|
||||
return vm_info
|
||||
|
||||
if (existing.st_mtime - int(time.time())) <= maxage:
|
||||
return True
|
||||
def _add_host(self, inv, parent_group, host_name):
|
||||
'''
|
||||
Add the host to the parent group in the given inventory.
|
||||
'''
|
||||
p_group = inv.setdefault(parent_group, [])
|
||||
if isinstance(p_group, dict):
|
||||
group_hosts = p_group.setdefault('hosts', [])
|
||||
else:
|
||||
group_hosts = p_group
|
||||
if host_name not in group_hosts:
|
||||
group_hosts.append(host_name)
|
||||
|
||||
return False
|
||||
def _add_child(self, inv, parent_group, child_group):
|
||||
'''
|
||||
Add a child group to a parent group in the given inventory.
|
||||
'''
|
||||
if parent_group != 'all':
|
||||
p_group = inv.setdefault(parent_group, {})
|
||||
if not isinstance(p_group, dict):
|
||||
inv[parent_group] = {'hosts': p_group}
|
||||
p_group = inv[parent_group]
|
||||
group_children = p_group.setdefault('children', [])
|
||||
if child_group not in group_children:
|
||||
group_children.append(child_group)
|
||||
inv.setdefault(child_group, [])
|
||||
|
||||
def get_host_info(host):
|
||||
''' Get variables about a specific host '''
|
||||
def get_inventory(self, meta_hostvars=True):
|
||||
'''
|
||||
Reads the inventory from cache or VMware API via pSphere.
|
||||
'''
|
||||
# Use different cache names for guests only vs. all hosts.
|
||||
if self.guests_only:
|
||||
cache_name = '__inventory_guests__'
|
||||
else:
|
||||
cache_name = '__inventory_all__'
|
||||
|
||||
hostinfo = {
|
||||
'vmware_name' : host.name,
|
||||
'vmware_tag' : host.tag,
|
||||
'vmware_parent': host.parent.name,
|
||||
}
|
||||
for k in host.capability.__dict__.keys():
|
||||
if k.startswith('_'):
|
||||
continue
|
||||
try:
|
||||
hostinfo['vmware_' + k] = str(host.capability[k])
|
||||
except:
|
||||
continue
|
||||
inv = self._get_cache(cache_name, None)
|
||||
if inv is not None:
|
||||
return inv
|
||||
|
||||
return hostinfo
|
||||
inv = {'all': {'hosts': []}}
|
||||
if meta_hostvars:
|
||||
inv['_meta'] = {'hostvars': {}}
|
||||
|
||||
|
||||
def get_inventory(client, config):
|
||||
''' Reads the inventory from cache or vmware api '''
|
||||
|
||||
if cache_available('inventory', config):
|
||||
inv = get_cache('inventory',config)
|
||||
else:
|
||||
inv= { 'all': {'hosts': []}, '_meta': { 'hostvars': {} } }
|
||||
default_group = os.path.basename(sys.argv[0]).rstrip('.py')
|
||||
|
||||
if config.has_option('defaults', 'guests_only'):
|
||||
guests_only = config.get('defaults', 'guests_only')
|
||||
else:
|
||||
guests_only = True
|
||||
|
||||
if not guests_only:
|
||||
if config.has_option('defaults','hw_group'):
|
||||
hw_group = config.get('defaults','hw_group')
|
||||
if not self.guests_only:
|
||||
if self.config.has_option('defaults', 'hw_group'):
|
||||
hw_group = self.config.get('defaults', 'hw_group')
|
||||
else:
|
||||
hw_group = default_group + '_hw'
|
||||
inv[hw_group] = []
|
||||
|
||||
if config.has_option('defaults','vm_group'):
|
||||
vm_group = config.get('defaults','vm_group')
|
||||
if self.config.has_option('defaults', 'vm_group'):
|
||||
vm_group = self.config.get('defaults', 'vm_group')
|
||||
else:
|
||||
vm_group = default_group + '_vm'
|
||||
inv[vm_group] = []
|
||||
|
||||
# Loop through physical hosts:
|
||||
hosts = HostSystem.all(client)
|
||||
for host in hosts:
|
||||
if not guests_only:
|
||||
inv['all']['hosts'].append(host.name)
|
||||
inv[hw_group].append(host.name)
|
||||
if host.tag:
|
||||
taggroup = 'vmware_' + host.tag
|
||||
if taggroup in inv:
|
||||
inv[taggroup].append(host.name)
|
||||
else:
|
||||
inv[taggroup] = [ host.name ]
|
||||
for host in HostSystem.all(self.client):
|
||||
|
||||
inv['_meta']['hostvars'][host.name] = get_host_info(host)
|
||||
save_cache(vm.name, inv['_meta']['hostvars'][host.name], config)
|
||||
if not self.guests_only:
|
||||
self._add_host(inv, 'all', host.name)
|
||||
self._add_host(inv, hw_group, host.name)
|
||||
if host.tag: # FIXME: Is this always a string?
|
||||
host_tag = 'vmware_%s' % host.tag
|
||||
self._add_host(inv, host_tag, host.name)
|
||||
|
||||
host_info = self._get_host_info(host)
|
||||
if meta_hostvars:
|
||||
inv['_meta']['hostvars'][host.name] = host_info
|
||||
self._put_cache(host.name, host_info)
|
||||
|
||||
# Loop through all VMs on physical host.
|
||||
for vm in host.vm:
|
||||
inv['all']['hosts'].append(vm.name)
|
||||
inv[vm_group].append(vm.name)
|
||||
for tag in vm.tag:
|
||||
taggroup = 'vmware_' + tag.key.lower()
|
||||
if taggroup in inv:
|
||||
inv[taggroup].append(vm.name)
|
||||
else:
|
||||
inv[taggroup] = [ vm.name ]
|
||||
self._add_host(inv, 'all', vm.name)
|
||||
self._add_host(inv, vm_group, vm.name)
|
||||
if vm.tag: # FIXME: Is this always a string?
|
||||
vm_tag = 'vmware_%s' % vm.tag
|
||||
self._add_host(inv, vm_tag, vm.name)
|
||||
vm_info = self._get_vm_info(vm)
|
||||
if meta_hostvars:
|
||||
inv['_meta']['hostvars'][vm.name] = vm_info
|
||||
self._put_cache(vm.name, vm_info)
|
||||
|
||||
inv['_meta']['hostvars'][vm.name] = get_host_info(host)
|
||||
save_cache(vm.name, inv['_meta']['hostvars'][vm.name], config)
|
||||
# Group by resource pool.
|
||||
vm_resourcePool = vm_info.get('vmware_resourcePool', None)
|
||||
if vm_resourcePool:
|
||||
self._add_child(inv, vm_group, 'resource_pools')
|
||||
self._add_child(inv, 'resource_pools', vm_resourcePool)
|
||||
self._add_host(inv, vm_resourcePool, vm.name)
|
||||
|
||||
save_cache('inventory', inv, config)
|
||||
return json.dumps(inv)
|
||||
# Group by datastore.
|
||||
for vm_datastore in vm_info.get('vmware_datastores', []):
|
||||
self._add_child(inv, vm_group, 'datastores')
|
||||
self._add_child(inv, 'datastores', vm_datastore)
|
||||
self._add_host(inv, vm_datastore, vm.name)
|
||||
|
||||
def get_single_host(client, config, hostname):
|
||||
# Group by network.
|
||||
for vm_network in vm_info.get('vmware_networks', []):
|
||||
self._add_child(inv, vm_group, 'networks')
|
||||
self._add_child(inv, 'networks', vm_network)
|
||||
self._add_host(inv, vm_network, vm.name)
|
||||
|
||||
inv = {}
|
||||
# Group by guest OS.
|
||||
vm_guestId = vm_info.get('vmware_guestId', None)
|
||||
if vm_guestId:
|
||||
self._add_child(inv, vm_group, 'guests')
|
||||
self._add_child(inv, 'guests', vm_guestId)
|
||||
self._add_host(inv, vm_guestId, vm.name)
|
||||
|
||||
if cache_available(hostname, config):
|
||||
inv = get_cache(hostname,config)
|
||||
self._put_cache(cache_name, inv)
|
||||
return inv
|
||||
|
||||
def get_host(self, hostname):
|
||||
'''
|
||||
Read info about a specific host or VM from cache or VMware API.
|
||||
'''
|
||||
inv = self._get_cache(hostname, None)
|
||||
if inv is not None:
|
||||
return inv
|
||||
|
||||
if not self.guests_only:
|
||||
try:
|
||||
host = HostSystem.get(self.client, name=hostname)
|
||||
inv = self._get_host_info(host)
|
||||
except ObjectNotFoundError:
|
||||
pass
|
||||
|
||||
if inv is None:
|
||||
try:
|
||||
vm = VirtualMachine.get(self.client, name=hostname)
|
||||
inv = self._get_vm_info(vm)
|
||||
except ObjectNotFoundError:
|
||||
pass
|
||||
|
||||
if inv is not None:
|
||||
self._put_cache(hostname, inv)
|
||||
return inv or {}
|
||||
|
||||
|
||||
def main():
|
||||
parser = optparse.OptionParser()
|
||||
parser.add_option('--list', action='store_true', dest='list',
|
||||
default=False, help='Output inventory groups and hosts')
|
||||
parser.add_option('--host', dest='host', default=None, metavar='HOST',
|
||||
help='Output variables only for the given hostname')
|
||||
# Additional options for use when running the script standalone, but never
|
||||
# used by Ansible.
|
||||
parser.add_option('--pretty', action='store_true', dest='pretty',
|
||||
default=False, help='Output nicely-formatted JSON')
|
||||
parser.add_option('--include-host-systems', action='store_true',
|
||||
dest='include_host_systems', default=False,
|
||||
help='Include host systems in addition to VMs')
|
||||
parser.add_option('--no-meta-hostvars', action='store_false',
|
||||
dest='meta_hostvars', default=True,
|
||||
help='Exclude [\'_meta\'][\'hostvars\'] with --list')
|
||||
options, args = parser.parse_args()
|
||||
|
||||
if options.include_host_systems:
|
||||
vmware_inventory = VMwareInventory(guests_only=False)
|
||||
else:
|
||||
hosts = HostSystem.all(client) #TODO: figure out single host getter
|
||||
for host in hosts:
|
||||
if hostname == host.name:
|
||||
inv = get_host_info(host)
|
||||
break
|
||||
for vm in host.vm:
|
||||
if hostname == vm.name:
|
||||
inv = get_host_info(host)
|
||||
break
|
||||
save_cache(hostname,inv,config)
|
||||
vmware_inventory = VMwareInventory()
|
||||
if options.host is not None:
|
||||
inventory = vmware_inventory.get_host(options.host)
|
||||
else:
|
||||
inventory = vmware_inventory.get_inventory(options.meta_hostvars)
|
||||
|
||||
json_kwargs = {}
|
||||
if options.pretty:
|
||||
json_kwargs.update({'indent': 4, 'sort_keys': True})
|
||||
json.dump(inventory, sys.stdout, **json_kwargs)
|
||||
|
||||
return json.dumps(inv)
|
||||
|
||||
if __name__ == '__main__':
|
||||
inventory = {}
|
||||
hostname = None
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
if sys.argv[1] == "--host":
|
||||
hostname = sys.argv[2]
|
||||
|
||||
# Read config
|
||||
config = ConfigParser.SafeConfigParser(
|
||||
defaults={'host': '', 'user': '', 'password': ''},
|
||||
)
|
||||
for section in ('auth', 'defaults'):
|
||||
config.add_section(section)
|
||||
for configfilename in [os.path.abspath(sys.argv[0]).rstrip('.py') + '.ini', 'vmware.ini']:
|
||||
if os.path.exists(configfilename):
|
||||
config.read(configfilename)
|
||||
break
|
||||
|
||||
auth_host, auth_user, auth_password = None, None, None
|
||||
|
||||
# Read our authentication information from the INI file, if it exists.
|
||||
try:
|
||||
auth_host = config.get('auth', 'host')
|
||||
auth_user = config.get('auth', 'user')
|
||||
auth_password = config.get('auth', 'password')
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# If any of the VMware environment variables are set, they trump
|
||||
# the INI configuration.
|
||||
if 'VMWARE_HOST' in os.environ:
|
||||
auth_host = os.environ['VMWARE_HOST']
|
||||
if 'VMWARE_USER' in os.environ:
|
||||
auth_user = os.environ['VMWARE_USER']
|
||||
if 'VMWARE_PASSWORD' in os.environ:
|
||||
auth_password = os.environ['VMWARE_PASSWORD']
|
||||
|
||||
# Create the VMware client.
|
||||
client = Client(auth_host, auth_user, auth_password)
|
||||
|
||||
# Actually do the work.
|
||||
if hostname is None:
|
||||
inventory = get_inventory(client, config)
|
||||
else:
|
||||
inventory = get_single_host(client, config, hostname)
|
||||
|
||||
# Return to Ansible.
|
||||
print inventory
|
||||
main()
|
||||
|
||||
@ -399,11 +399,11 @@ VMWARE_REGIONS_BLACKLIST = []
|
||||
|
||||
# Inventory variable name/values for determining whether a host is
|
||||
# active in vSphere.
|
||||
VMWARE_ENABLED_VAR = 'status'
|
||||
VMWARE_ENABLED_VALUE = 'POWERED ON'
|
||||
VMWARE_ENABLED_VAR = 'vmware_powerState'
|
||||
VMWARE_ENABLED_VALUE = 'poweredOn'
|
||||
|
||||
# Inventory variable name containing the unique instance ID.
|
||||
VMWARE_INSTANCE_ID_VAR = 'guest_id'
|
||||
VMWARE_INSTANCE_ID_VAR = 'vmware_uuid'
|
||||
|
||||
# Filter for allowed group and host names when importing inventory
|
||||
# from EC2.
|
||||
|
||||
@ -484,3 +484,8 @@ TEST_AWS_REGIONS = 'all'
|
||||
TEST_RACKSPACE_USERNAME = ''
|
||||
TEST_RACKSPACE_API_KEY = ''
|
||||
TEST_RACKSPACE_REGIONS = 'all'
|
||||
|
||||
# VMware credentials
|
||||
TEST_VMWARE_HOST = ''
|
||||
TEST_VMWARE_USER = ''
|
||||
TEST_VMWARE_PASSWORD = ''
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
|
||||
tooltip_delay: {show: 500, hide: 100}, // Default number of milliseconds to delay displaying/hiding tooltips
|
||||
|
||||
debug_mode: false, // Enable console logging messages
|
||||
debug_mode: true, // Enable console logging messages
|
||||
|
||||
password_strength: 45, // User password strength. Integer between 0 and 100, 100 being impossibly strong.
|
||||
// This value controls progress bar colors:
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
|
||||
function JobTemplatesList($scope, $rootScope, $location, $log, $routeParams, Rest, Alert, JobTemplateList,
|
||||
GenerateList, LoadBreadCrumbs, Prompt, SearchInit, PaginateInit, ReturnToCaller, ClearScope, ProcessErrors,
|
||||
GetBasePath, JobTemplateForm, CredentialList, LookUpInit, PlaybookRun, Wait, Stream) {
|
||||
GetBasePath, JobTemplateForm, CredentialList, LookUpInit, PlaybookRun, Wait, Stream, CreateDialog, $compile) {
|
||||
|
||||
ClearScope();
|
||||
|
||||
@ -97,6 +97,138 @@ function JobTemplatesList($scope, $rootScope, $location, $log, $routeParams, Res
|
||||
});
|
||||
};
|
||||
|
||||
$scope.copyJobTemplate = function(id, name){
|
||||
var element,
|
||||
buttons = [{
|
||||
"label": "Cancel",
|
||||
"onClick": function() {
|
||||
$(this).dialog('close');
|
||||
},
|
||||
"icon": "fa-times",
|
||||
"class": "btn btn-default",
|
||||
"id": "copy-close-button"
|
||||
},{
|
||||
"label": "Copy",
|
||||
"onClick": function() {
|
||||
copyAction();
|
||||
// setTimeout(function(){
|
||||
// scope.$apply(function(){
|
||||
// if(mode==='survey-taker'){
|
||||
// scope.$emit('SurveyTakerCompleted');
|
||||
// } else{
|
||||
// scope.saveSurvey();
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
},
|
||||
"icon": "fa-copy",
|
||||
"class": "btn btn-primary",
|
||||
"id": "job-copy-button"
|
||||
}],
|
||||
copyAction = function () {
|
||||
// retrieve the copy of the job template object from the api, then overwrite the name and throw away the id
|
||||
Wait('start');
|
||||
var url = defaultUrl + id + '/';
|
||||
Rest.setUrl(url);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
data.name = $scope.new_copy_name;
|
||||
delete data.id;
|
||||
$scope.$emit('GoToCopy', data);
|
||||
})
|
||||
.error(function (data) {
|
||||
Wait('stop');
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status });
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
CreateDialog({
|
||||
id: 'copy-job-modal' ,
|
||||
title: "Copy",
|
||||
scope: $scope,
|
||||
buttons: buttons,
|
||||
width: 500,
|
||||
height: 300,
|
||||
minWidth: 200,
|
||||
callback: 'CopyDialogReady'
|
||||
});
|
||||
|
||||
$('#job_name').text(name);
|
||||
$('#copy-job-modal').show();
|
||||
|
||||
|
||||
if ($scope.removeCopyDialogReady) {
|
||||
$scope.removeCopyDialogReady();
|
||||
}
|
||||
$scope.removeCopyDialogReady = $scope.$on('CopyDialogReady', function() {
|
||||
$('#copy-job-modal').dialog('open');
|
||||
$('#job-copy-button').attr('ng-disabled', "!copy_form.$valid");
|
||||
element = angular.element(document.getElementById('job-copy-button'));
|
||||
$compile(element)($scope);
|
||||
});
|
||||
|
||||
if ($scope.removeGoToCopy) {
|
||||
$scope.removeGoToCopy();
|
||||
}
|
||||
$scope.removeGoToCopy = $scope.$on('GoToCopy', function(e, data) {
|
||||
var url = defaultUrl,
|
||||
old_survey_url = (data.related.survey_spec) ? data.related.survey_spec : "" ;
|
||||
Rest.setUrl(url);
|
||||
Rest.post(data)
|
||||
.success(function (data) {
|
||||
if(data.survey_enabled===true){
|
||||
$scope.$emit("CopySurvey", data, old_survey_url);
|
||||
}
|
||||
else {
|
||||
$('#copy-job-modal').dialog('close');
|
||||
Wait('stop');
|
||||
$location.path($location.path() + '/' + data.id);
|
||||
}
|
||||
|
||||
})
|
||||
.error(function (data) {
|
||||
Wait('stop');
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Call to ' + url + ' failed. DELETE returned status: ' + status });
|
||||
});
|
||||
});
|
||||
|
||||
if ($scope.removeCopySurvey) {
|
||||
$scope.removeCopySurvey();
|
||||
}
|
||||
$scope.removeCopySurvey = $scope.$on('CopySurvey', function(e, new_data, old_url) {
|
||||
// var url = data.related.survey_spec;
|
||||
Rest.setUrl(old_url);
|
||||
Rest.get()
|
||||
.success(function (survey_data) {
|
||||
|
||||
Rest.setUrl(new_data.related.survey_spec);
|
||||
Rest.post(survey_data)
|
||||
.success(function () {
|
||||
$('#copy-job-modal').dialog('close');
|
||||
Wait('stop');
|
||||
$location.path($location.path() + '/' + new_data.id);
|
||||
})
|
||||
.error(function (data) {
|
||||
Wait('stop');
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Call to ' + new_data.related.survey_spec + ' failed. DELETE returned status: ' + status });
|
||||
});
|
||||
|
||||
|
||||
})
|
||||
.error(function (data) {
|
||||
Wait('stop');
|
||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!',
|
||||
msg: 'Call to ' + old_url + ' failed. DELETE returned status: ' + status });
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
$scope.submitJob = function (id) {
|
||||
PlaybookRun({ scope: $scope, id: id });
|
||||
};
|
||||
@ -105,7 +237,7 @@ function JobTemplatesList($scope, $rootScope, $location, $log, $routeParams, Res
|
||||
JobTemplatesList.$inject = ['$scope', '$rootScope', '$location', '$log', '$routeParams', 'Rest', 'Alert', 'JobTemplateList',
|
||||
'GenerateList', 'LoadBreadCrumbs', 'Prompt', 'SearchInit', 'PaginateInit', 'ReturnToCaller', 'ClearScope',
|
||||
'ProcessErrors', 'GetBasePath', 'JobTemplateForm', 'CredentialList', 'LookUpInit',
|
||||
'PlaybookRun', 'Wait', 'Stream'
|
||||
'PlaybookRun', 'Wait', 'Stream', 'CreateDialog' , '$compile'
|
||||
];
|
||||
|
||||
function JobTemplatesAdd($scope, $rootScope, $compile, $location, $log, $routeParams, JobTemplateForm,
|
||||
@ -339,18 +471,21 @@ function JobTemplatesAdd($scope, $rootScope, $compile, $location, $log, $routePa
|
||||
.success(function(data) {
|
||||
$scope.$emit('templateSaveSuccess', data);
|
||||
|
||||
//once the job template information is saved we submit the survey info to the correct endpoint
|
||||
var url = data.url+ 'survey_spec/';
|
||||
Rest.setUrl(url);
|
||||
Rest.post({ name: $scope.survey_name, description: $scope.survey_description, spec: $scope.survey_questions })
|
||||
.success(function () {
|
||||
Wait('stop');
|
||||
if(data.survey_enabled===true){
|
||||
//once the job template information is saved we submit the survey info to the correct endpoint
|
||||
var url = data.url+ 'survey_spec/';
|
||||
Rest.setUrl(url);
|
||||
Rest.post({ name: $scope.survey_name, description: $scope.survey_description, spec: $scope.survey_questions })
|
||||
.success(function () {
|
||||
Wait('stop');
|
||||
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, form, { hdr: 'Error!',
|
||||
msg: 'Failed to add new survey. Post returned status: ' + status });
|
||||
});
|
||||
}
|
||||
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, form, { hdr: 'Error!',
|
||||
msg: 'Failed to add new survey. Post returned status: ' + status });
|
||||
});
|
||||
|
||||
})
|
||||
.error(function (data, status) {
|
||||
@ -413,8 +548,7 @@ function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log, $routeP
|
||||
Alert, ProcessErrors, LoadBreadCrumbs, RelatedSearchInit, RelatedPaginateInit, ReturnToCaller, ClearScope, InventoryList,
|
||||
CredentialList, ProjectList, LookUpInit, GetBasePath, md5Setup, ParseTypeChange, JobStatusToolTip, FormatDate,
|
||||
Wait, Stream, Empty, Prompt, ParseVariableString, ToJSON, SchedulesControllerInit, JobsControllerInit, JobsListUpdate,
|
||||
GetChoices, SchedulesListInit, SchedulesList, CallbackHelpInit, PlaybookRun, SurveyControllerInit)
|
||||
{
|
||||
GetChoices, SchedulesListInit, SchedulesList, CallbackHelpInit, PlaybookRun, SurveyControllerInit){
|
||||
|
||||
ClearScope();
|
||||
|
||||
@ -429,6 +563,7 @@ function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log, $routeP
|
||||
checkSCMStatus, getPlaybooks, callback,
|
||||
choicesCount = 0;
|
||||
|
||||
|
||||
CallbackHelpInit({ scope: $scope });
|
||||
|
||||
SchedulesList.well = false;
|
||||
@ -703,122 +838,7 @@ function JobTemplatesEdit($scope, $rootScope, $compile, $location, $log, $routeP
|
||||
$scope.rmoveLoadJobs();
|
||||
}
|
||||
$scope.removeLoadJobs = $scope.$on('LoadJobs', function() {
|
||||
// Retrieve detail record and prepopulate the form
|
||||
Rest.setUrl(defaultUrl + id);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
var fld, i;
|
||||
LoadBreadCrumbs({ path: '/job_templates/' + id, title: data.name });
|
||||
for (fld in form.fields) {
|
||||
if (fld !== 'variables' && data[fld] !== null && data[fld] !== undefined) {
|
||||
if (form.fields[fld].type === 'select') {
|
||||
if ($scope[fld + '_options'] && $scope[fld + '_options'].length > 0) {
|
||||
for (i = 0; i < $scope[fld + '_options'].length; i++) {
|
||||
if (data[fld] === $scope[fld + '_options'][i].value) {
|
||||
$scope[fld] = $scope[fld + '_options'][i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$scope[fld] = data[fld];
|
||||
}
|
||||
} else {
|
||||
$scope[fld] = data[fld];
|
||||
if(fld ==='survey_enabled'){
|
||||
// $scope.$emit('EnableSurvey', fld);
|
||||
$('#job_templates_survey_enabled_chbox').attr('checked', $scope[fld]);
|
||||
if(Empty(data.summary_fields.survey)) {
|
||||
$('#job_templates_delete_survey_btn').hide();
|
||||
$('#job_templates_edit_survey_btn').hide();
|
||||
$('#job_templates_create_survey_btn').show();
|
||||
}
|
||||
else{
|
||||
$('#job_templates_delete_survey_btn').show();
|
||||
$('#job_templates_edit_survey_btn').show();
|
||||
$('#job_templates_create_survey_btn').hide();
|
||||
$scope.survey_exists = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
master[fld] = $scope[fld];
|
||||
}
|
||||
if (fld === 'variables') {
|
||||
// Parse extra_vars, converting to YAML.
|
||||
$scope.variables = ParseVariableString(data.extra_vars);
|
||||
master.variables = $scope.variables;
|
||||
}
|
||||
if (form.fields[fld].type === 'lookup' && data.summary_fields[form.fields[fld].sourceModel]) {
|
||||
$scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] =
|
||||
data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField];
|
||||
master[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] =
|
||||
$scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField];
|
||||
}
|
||||
}
|
||||
|
||||
$scope.url = data.url;
|
||||
|
||||
$scope.ask_variables_on_launch = (data.ask_variables_on_launch) ? 'true' : 'false';
|
||||
master.ask_variables_on_launch = $scope.ask_variables_on_launch;
|
||||
|
||||
relatedSets = form.relatedSets(data.related);
|
||||
|
||||
if (data.host_config_key) {
|
||||
$scope.example_config_key = data.host_config_key;
|
||||
}
|
||||
$scope.example_template_id = id;
|
||||
$scope.setCallbackHelp();
|
||||
|
||||
$scope.callback_url = $scope.callback_server_path + ((data.related.callback) ? data.related.callback :
|
||||
GetBasePath('job_templates') + id + '/callback/');
|
||||
master.callback_url = $scope.callback_url;
|
||||
|
||||
LookUpInit({
|
||||
scope: $scope,
|
||||
form: form,
|
||||
current_item: data.inventory,
|
||||
list: InventoryList,
|
||||
field: 'inventory',
|
||||
input_type: "radio"
|
||||
});
|
||||
|
||||
LookUpInit({
|
||||
url: GetBasePath('credentials') + '?kind=ssh',
|
||||
scope: $scope,
|
||||
form: form,
|
||||
current_item: data.credential,
|
||||
list: CredentialList,
|
||||
field: 'credential',
|
||||
hdr: 'Select Machine Credential',
|
||||
input_type: "radio"
|
||||
});
|
||||
|
||||
LookUpInit({
|
||||
scope: $scope,
|
||||
form: form,
|
||||
current_item: data.project,
|
||||
list: ProjectList,
|
||||
field: 'project',
|
||||
input_type: "radio"
|
||||
});
|
||||
|
||||
RelatedSearchInit({
|
||||
scope: $scope,
|
||||
form: form,
|
||||
relatedSets: relatedSets
|
||||
});
|
||||
|
||||
RelatedPaginateInit({
|
||||
scope: $scope,
|
||||
relatedSets: relatedSets
|
||||
});
|
||||
|
||||
$scope.$emit('jobTemplateLoaded', data.related.cloud_credential);
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors($scope, data, status, form, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to retrieve job template: ' + $routeParams.template_id + '. GET status: ' + status
|
||||
});
|
||||
});
|
||||
$scope.fillJobTemplate();
|
||||
});
|
||||
|
||||
if ($scope.removeChoicesReady) {
|
||||
|
||||
@ -79,6 +79,8 @@ function JobsListController ($rootScope, $log, $scope, $compile, $routeParams, C
|
||||
queued_scope.search('queued_job');
|
||||
break;
|
||||
case 'successful':
|
||||
completed_scope.search('completed_job');
|
||||
break;
|
||||
case 'failed':
|
||||
case 'error':
|
||||
case 'canceled':
|
||||
|
||||
@ -31,8 +31,7 @@ function PortalController($scope, $compile, $routeParams, $rootScope, $location,
|
||||
|
||||
var html,
|
||||
e,
|
||||
// winHeight,
|
||||
// available_height,
|
||||
jobs_scope,
|
||||
list = PortalJobTemplateList,
|
||||
view= GenerateList,
|
||||
defaultUrl = GetBasePath('job_templates'),
|
||||
@ -112,12 +111,60 @@ function PortalController($scope, $compile, $routeParams, $rootScope, $location,
|
||||
if ($scope.removeWidgetLoaded) {
|
||||
$scope.removeWidgetLoaded();
|
||||
}
|
||||
$scope.removeWidgetLoaded = $scope.$on('WidgetLoaded', function () {
|
||||
$scope.removeWidgetLoaded = $scope.$on('WidgetLoaded', function (e, label, jobscope) {
|
||||
if(label==="portal_jobs"){
|
||||
jobs_scope = jobscope;
|
||||
}
|
||||
$('.actions-column:eq(0)').text('Launch');
|
||||
$('.actions-column:eq(1)').text('Details');
|
||||
$('.list-well:eq(1)').css('margin-top' , '0px');
|
||||
});
|
||||
|
||||
// function processEvent(event) {
|
||||
// switch(event.status) {
|
||||
// case 'running':
|
||||
// jobs_scope.search('running_job');
|
||||
// jobs_scope.search('queued_job');
|
||||
|
||||
// break;
|
||||
// case 'new':
|
||||
// case 'pending':
|
||||
// case 'waiting':
|
||||
// jobs_scope.search('queued_job');
|
||||
|
||||
// break;
|
||||
// case 'successful':
|
||||
// jobs_scope.search('completed_job');
|
||||
// case 'failed':
|
||||
// case 'error':
|
||||
// case 'canceled':
|
||||
// jobs_scope.search('completed_job');
|
||||
// jobs_scope.search('running_job');
|
||||
// jobs_scope.search('queued_job');
|
||||
// }
|
||||
// }
|
||||
|
||||
if ($rootScope.removeJobStatusChange) {
|
||||
$rootScope.removeJobStatusChange();
|
||||
}
|
||||
$rootScope.removeJobStatusChange = $rootScope.$on('JobStatusChange', function() {
|
||||
jobs_scope.refreshJobs();
|
||||
// if(data.status==='pending'){
|
||||
// // $scope.refresh();
|
||||
// $('#portal-jobs').empty();
|
||||
// // $rootScope.flashMessage = null;
|
||||
// PortalJobsWidget({
|
||||
// scope: $scope,
|
||||
// target: 'portal-jobs',
|
||||
// searchSize: 'col-lg-6 col-md-6'
|
||||
// });
|
||||
// }
|
||||
|
||||
|
||||
//x`processEvent(data);
|
||||
|
||||
});
|
||||
|
||||
$scope.submitJob = function (id) {
|
||||
PlaybookRun({ scope: $scope, id: id });
|
||||
};
|
||||
|
||||
@ -760,7 +760,7 @@ function($location, Wait, GetBasePath, LookUpInit, JobTemplateForm, CredentialLi
|
||||
}
|
||||
scope.removePlaybookLaunchFinished = scope.$on('PlaybookLaunchFinished', function(e, data) {
|
||||
//var base = $location.path().replace(/^\//, '').split('/')[0];
|
||||
if(scope.portalMode===false){
|
||||
if(scope.portalMode===false || scope.$parent.portalMode===false){
|
||||
$location.path('/jobs/' + data.job);
|
||||
}
|
||||
|
||||
|
||||
@ -19,10 +19,24 @@ angular.module('JobTemplatesHelper', ['Utilities'])
|
||||
* Add bits to $scope for handling callback url help
|
||||
*
|
||||
*/
|
||||
.factory('CallbackHelpInit', ['$location', 'GetBasePath', function($location, GetBasePath) {
|
||||
|
||||
.factory('CallbackHelpInit', ['$location', 'GetBasePath', 'Rest', 'JobTemplateForm', 'GenerateForm', '$routeParams', 'LoadBreadCrumbs', 'ProcessErrors', 'ParseTypeChange',
|
||||
'ParseVariableString', 'Empty', 'LookUpInit', 'InventoryList', 'CredentialList','ProjectList', 'RelatedSearchInit', 'RelatedPaginateInit',
|
||||
function($location, GetBasePath, Rest, JobTemplateForm, GenerateForm, $routeParams, LoadBreadCrumbs, ProcessErrors,ParseTypeChange,
|
||||
ParseVariableString, Empty, LookUpInit, InventoryList, CredentialList, ProjectList, RelatedSearchInit, RelatedPaginateInit) {
|
||||
return function(params) {
|
||||
|
||||
var scope = params.scope;
|
||||
var scope = params.scope,
|
||||
defaultUrl = GetBasePath('job_templates'),
|
||||
// generator = GenerateForm,
|
||||
form = JobTemplateForm(),
|
||||
// loadingFinishedCount = 0,
|
||||
// base = $location.path().replace(/^\//, '').split('/')[0],
|
||||
master = {},
|
||||
id = $routeParams.template_id,
|
||||
relatedSets = {};
|
||||
// checkSCMStatus, getPlaybooks, callback,
|
||||
// choicesCount = 0;
|
||||
|
||||
// The form uses awPopOverWatch directive to 'watch' scope.callback_help for changes. Each time the
|
||||
// popover is activated, a function checks the value of scope.callback_help before constructing the content.
|
||||
@ -56,8 +70,132 @@ angular.module('JobTemplatesHelper', ['Utilities'])
|
||||
scope.example_config_key = '5a8ec154832b780b9bdef1061764ae5a';
|
||||
scope.example_template_id = 'N';
|
||||
scope.setCallbackHelp();
|
||||
|
||||
scope.fillJobTemplate = function(){
|
||||
// id = id || $rootScope.copy.id;
|
||||
// Retrieve detail record and prepopulate the form
|
||||
Rest.setUrl(defaultUrl + id);
|
||||
Rest.get()
|
||||
.success(function (data) {
|
||||
var fld, i;
|
||||
LoadBreadCrumbs({ path: '/job_templates/' + id, title: data.name });
|
||||
for (fld in form.fields) {
|
||||
if (fld !== 'variables' && data[fld] !== null && data[fld] !== undefined) {
|
||||
if (form.fields[fld].type === 'select') {
|
||||
if (scope[fld + '_options'] && scope[fld + '_options'].length > 0) {
|
||||
for (i = 0; i < scope[fld + '_options'].length; i++) {
|
||||
if (data[fld] === scope[fld + '_options'][i].value) {
|
||||
scope[fld] = scope[fld + '_options'][i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
scope[fld] = data[fld];
|
||||
}
|
||||
} else {
|
||||
scope[fld] = data[fld];
|
||||
if(fld ==='survey_enabled'){
|
||||
// $scope.$emit('EnableSurvey', fld);
|
||||
$('#job_templates_survey_enabled_chbox').attr('checked', scope[fld]);
|
||||
if(Empty(data.summary_fields.survey)) {
|
||||
$('#job_templates_delete_survey_btn').hide();
|
||||
$('#job_templates_edit_survey_btn').hide();
|
||||
$('#job_templates_create_survey_btn').show();
|
||||
}
|
||||
else{
|
||||
$('#job_templates_delete_survey_btn').show();
|
||||
$('#job_templates_edit_survey_btn').show();
|
||||
$('#job_templates_create_survey_btn').hide();
|
||||
scope.survey_exists = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
master[fld] = scope[fld];
|
||||
}
|
||||
if (fld === 'variables') {
|
||||
// Parse extra_vars, converting to YAML.
|
||||
scope.variables = ParseVariableString(data.extra_vars);
|
||||
master.variables = scope.variables;
|
||||
}
|
||||
if (form.fields[fld].type === 'lookup' && data.summary_fields[form.fields[fld].sourceModel]) {
|
||||
scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] =
|
||||
data.summary_fields[form.fields[fld].sourceModel][form.fields[fld].sourceField];
|
||||
master[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField] =
|
||||
scope[form.fields[fld].sourceModel + '_' + form.fields[fld].sourceField];
|
||||
}
|
||||
}
|
||||
|
||||
scope.url = data.url;
|
||||
|
||||
scope.ask_variables_on_launch = (data.ask_variables_on_launch) ? 'true' : 'false';
|
||||
master.ask_variables_on_launch = scope.ask_variables_on_launch;
|
||||
|
||||
relatedSets = form.relatedSets(data.related);
|
||||
|
||||
if (data.host_config_key) {
|
||||
scope.example_config_key = data.host_config_key;
|
||||
}
|
||||
scope.example_template_id = id;
|
||||
scope.setCallbackHelp();
|
||||
|
||||
scope.callback_url = scope.callback_server_path + ((data.related.callback) ? data.related.callback :
|
||||
GetBasePath('job_templates') + id + '/callback/');
|
||||
master.callback_url = scope.callback_url;
|
||||
|
||||
LookUpInit({
|
||||
scope: scope,
|
||||
form: form,
|
||||
current_item: data.inventory,
|
||||
list: InventoryList,
|
||||
field: 'inventory',
|
||||
input_type: "radio"
|
||||
});
|
||||
|
||||
LookUpInit({
|
||||
url: GetBasePath('credentials') + '?kind=ssh',
|
||||
scope: scope,
|
||||
form: form,
|
||||
current_item: data.credential,
|
||||
list: CredentialList,
|
||||
field: 'credential',
|
||||
hdr: 'Select Machine Credential',
|
||||
input_type: "radio"
|
||||
});
|
||||
|
||||
LookUpInit({
|
||||
scope: scope,
|
||||
form: form,
|
||||
current_item: data.project,
|
||||
list: ProjectList,
|
||||
field: 'project',
|
||||
input_type: "radio"
|
||||
});
|
||||
|
||||
RelatedSearchInit({
|
||||
scope: scope,
|
||||
form: form,
|
||||
relatedSets: relatedSets
|
||||
});
|
||||
|
||||
RelatedPaginateInit({
|
||||
scope: scope,
|
||||
relatedSets: relatedSets
|
||||
});
|
||||
|
||||
|
||||
scope.$emit('jobTemplateLoaded', data.related.cloud_credential);
|
||||
})
|
||||
.error(function (data, status) {
|
||||
ProcessErrors(scope, data, status, form, {
|
||||
hdr: 'Error!',
|
||||
msg: 'Failed to retrieve job template: ' + $routeParams.template_id + '. GET status: ' + status
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
}]);
|
||||
|
||||
|
||||
|
||||
@ -32,6 +32,7 @@ angular.module('VariablesHelper', ['Utilities'])
|
||||
json_obj = JSON.parse(variables);
|
||||
json_obj = SortVariables(json_obj);
|
||||
result = jsyaml.safeDump(json_obj);
|
||||
|
||||
}
|
||||
catch (e) {
|
||||
$log.info('Attempt to parse extra_vars as JSON failed. Attempting to parse as YAML');
|
||||
@ -56,6 +57,7 @@ angular.module('VariablesHelper', ['Utilities'])
|
||||
try {
|
||||
json_obj = SortVariables(variables);
|
||||
result = jsyaml.safeDump(json_obj);
|
||||
// result = variables;
|
||||
}
|
||||
catch(e3) {
|
||||
ProcessErrors(null, variables, e3.message, null, { hdr: 'Error!',
|
||||
@ -78,7 +80,11 @@ angular.module('VariablesHelper', ['Utilities'])
|
||||
**/
|
||||
.factory('ToJSON', ['$log', 'ProcessErrors', function($log, ProcessErrors) {
|
||||
return function(parseType, variables, stringify, reviver) {
|
||||
var json_data, result;
|
||||
var json_data,
|
||||
result;
|
||||
// bracketVar,
|
||||
// key,
|
||||
// lines, i, newVars = [];
|
||||
if (parseType === 'json') {
|
||||
try {
|
||||
//parse a JSON string
|
||||
@ -97,7 +103,30 @@ angular.module('VariablesHelper', ['Utilities'])
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
// if(variables.indexOf('{{')>-1){
|
||||
// lines = variables.split(/\n/);
|
||||
// for(i=0; i<lines.length; i++){
|
||||
// if(lines[i].indexOf('{{')>-1){
|
||||
// lines[i] = lines[i].replace('{{', '"{{');
|
||||
// // lines[i] = lines[i].replace(lines[i].lastIndexOf('}}'), '}}"');
|
||||
// lines[i] = lines[i]+'"';
|
||||
// // newVars = newVars+ lines[i];
|
||||
// newVars.push(lines[i])
|
||||
|
||||
// }
|
||||
// }
|
||||
// json_data = jsyaml.load(newVars.toString());
|
||||
|
||||
// bracketVar = variables.substr(variables.indexOf('{{'), variables.indexOf('}}'));
|
||||
// bracketVar = bracketVar.trimRight();
|
||||
// key = variables.substr(0, variables.indexOf(':'));
|
||||
// json_data = jsyaml.load(variables);
|
||||
// json_data[key] = bracketVar;
|
||||
// }
|
||||
// else
|
||||
json_data = jsyaml.load(variables);
|
||||
|
||||
|
||||
}
|
||||
catch(e) {
|
||||
json_data = {};
|
||||
|
||||
@ -64,7 +64,6 @@ angular.module('JobTemplatesListDefinition', [])
|
||||
ngHref: '#/job_templates/{{ job_template.id }}/schedules',
|
||||
awToolTip: 'Schedule future job template runs',
|
||||
dataPlacement: 'top',
|
||||
ngHide: 'portalMode===true'
|
||||
},
|
||||
edit: {
|
||||
label: 'Edit',
|
||||
@ -72,7 +71,6 @@ angular.module('JobTemplatesListDefinition', [])
|
||||
awToolTip: 'Edit template',
|
||||
"class": 'btn-default btn-xs',
|
||||
dataPlacement: 'top',
|
||||
ngHide: 'portalMode===true'
|
||||
},
|
||||
"delete": {
|
||||
label: 'Delete',
|
||||
@ -80,7 +78,14 @@ angular.module('JobTemplatesListDefinition', [])
|
||||
"class": 'btn-danger btn-xs',
|
||||
awToolTip: 'Delete template',
|
||||
dataPlacement: 'top',
|
||||
ngHide: 'portalMode===true'
|
||||
},
|
||||
copy: {
|
||||
label: 'Copy',
|
||||
ngClick: "copyJobTemplate(job_template.id, job_template.name)",
|
||||
"class": 'btn-danger btn-xs',
|
||||
awToolTip: 'Copy template',
|
||||
dataPlacement: 'top',
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -19,6 +19,9 @@ angular.module('PortalJobsWidget', ['RestServices', 'Utilities'])
|
||||
choicesCount = 0,
|
||||
listCount = 0,
|
||||
jobs_scope = scope.$new(true),
|
||||
// completed_scope = scope.$new(true),
|
||||
// running_scope = scope.$new(true),
|
||||
// queued_scope = scope.$new(true),
|
||||
// scheduled_scope = scope.$new(true),
|
||||
max_rows,
|
||||
html, e;
|
||||
@ -56,7 +59,7 @@ angular.module('PortalJobsWidget', ['RestServices', 'Utilities'])
|
||||
listCount++;
|
||||
if (listCount === 1) {
|
||||
//api_complete = true;
|
||||
scope.$emit('WidgetLoaded', jobs_scope);
|
||||
scope.$emit('WidgetLoaded', "portal_jobs", jobs_scope);
|
||||
}
|
||||
});
|
||||
|
||||
@ -75,16 +78,36 @@ angular.module('PortalJobsWidget', ['RestServices', 'Utilities'])
|
||||
id: 'active-jobs',
|
||||
url: GetBasePath('unified_jobs') + '?status__in=running,completed,failed,successful,error,canceled',
|
||||
pageSize: max_rows,
|
||||
spinner: false
|
||||
spinner: true
|
||||
});
|
||||
// LoadSchedulesScope({
|
||||
|
||||
// completed_scope.showJobType = true;
|
||||
// LoadJobsScope({
|
||||
// parent_scope: scope,
|
||||
// scope: scheduled_scope,
|
||||
// list: ScheduledJobsList,
|
||||
// id: 'scheduled-jobs-tab',
|
||||
// url: GetBasePath('schedules') + '?next_run__isnull=false',
|
||||
// pageSize: max_rows,
|
||||
// spinner: false
|
||||
// scope: completed_scope,
|
||||
// list: PortalJobsList,
|
||||
// id: 'active-jobs',
|
||||
// url: GetBasePath('unified_jobs') + '?or__status=successful&or__status=failed&or__status=error&or__status=canceled',
|
||||
// // searchParams: search_params,
|
||||
// pageSize: max_rows
|
||||
// });
|
||||
|
||||
// LoadJobsScope({
|
||||
// parent_scope: scope,
|
||||
// scope: running_scope,
|
||||
// list: PortalJobsList,
|
||||
// id: 'active-jobs',
|
||||
// url: GetBasePath('unified_jobs') + '?status=running',
|
||||
// pageSize: max_rows
|
||||
// });
|
||||
|
||||
// LoadJobsScope({
|
||||
// parent_scope: scope,
|
||||
// scope: queued_scope,
|
||||
// list: PortalJobsList,
|
||||
// id: 'active-jobs',
|
||||
// url: GetBasePath('unified_jobs') + '?or__status=pending&or__status=waiting&or__status=new',
|
||||
// pageSize: max_rows
|
||||
// });
|
||||
|
||||
$(window).resize(_.debounce(function() {
|
||||
|
||||
@ -27,7 +27,9 @@ angular.module('SocketIO', ['AuthService', 'Utilities'])
|
||||
host = $location.host(),
|
||||
endpoint = params.endpoint,
|
||||
protocol = $location.protocol(),
|
||||
config, socketPort, url;
|
||||
config, socketPort,
|
||||
// handshakeData,
|
||||
url;
|
||||
|
||||
// Since some pages are opened in a new tab, we might get here before AnsibleConfig is available.
|
||||
// In that case, load from local storage.
|
||||
@ -61,14 +63,23 @@ angular.module('SocketIO', ['AuthService', 'Utilities'])
|
||||
scope: scope,
|
||||
url: url,
|
||||
socket: null,
|
||||
|
||||
init: function() {
|
||||
var self = this,
|
||||
token = Authorization.getToken();
|
||||
if (!$rootScope.sessionTimer || ($rootScope.sessionTimer && !$rootScope.sessionTimer.isExpired())) {
|
||||
// We have a valid session token, so attmempt socket connection
|
||||
// We have a valid session token, so attempt socket connection
|
||||
$log.debug('Socket connecting to: ' + url);
|
||||
self.scope.socket_url = url;
|
||||
self.socket = io.connect(url, { headers:
|
||||
// handshakeData = {
|
||||
// headers: {
|
||||
// 'Authorization': 'Token ' + token,
|
||||
// 'X-Auth-Token': 'Token ' + token
|
||||
// }
|
||||
// }
|
||||
|
||||
self.socket = io.connect(url, {
|
||||
headers:
|
||||
{
|
||||
'Authorization': 'Token ' + token,
|
||||
'X-Auth-Token': 'Token ' + token
|
||||
@ -77,7 +88,9 @@ angular.module('SocketIO', ['AuthService', 'Utilities'])
|
||||
'try multiple transports': false,
|
||||
'max reconneciton attemps': 3,
|
||||
'reconnection limit': 3000,
|
||||
'force new connection': true,
|
||||
});
|
||||
|
||||
self.socket.on('connection', function() {
|
||||
$log.debug('Socket connecting...');
|
||||
self.scope.$apply(function () {
|
||||
|
||||
@ -159,7 +159,7 @@ angular.module('GeneratorHelpers', [])
|
||||
icon = 'fa-list-ul';
|
||||
break;
|
||||
case 'copy':
|
||||
icon = "fa-cut";
|
||||
icon = "fa-copy";
|
||||
break;
|
||||
}
|
||||
icon += (size) ? " " + size : "";
|
||||
|
||||
@ -20,8 +20,8 @@
|
||||
<a href="/#/jobs/{{ job_id }}/stdout" id="view-stdout-button" target="_blank" type="button" class="btn btn-primary btn-xs" aw-tool-tip="View standard out. Opens in new tab or window." data-placement="top"><i class="fa fa-external-link"></i></a>
|
||||
<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"></i></button>
|
||||
<a href="" ng-click="deleteJob()" id="cancel-job-button" ng-show="job_status.status == 'running'" type="button" class="btn btn-primary btn-xs" aw-tool-tip="Cancel" data-placement="top"><i class="fa fa-minus-circle"></i></a>
|
||||
<a href="" ng-click="deleteJob()" id="delete-job-button" ng-show="job_status.status != 'running'" type="button" class="btn btn-primary btn-xs" aw-tool-tip="Delete" data-placement="top"><i class="fa fa-trash-o"></i></a>
|
||||
<a href="" ng-click="deleteJob()" id="cancel-job-button" ng-show="job_status.status == 'running' || job_status.status=='pending' " type="button" class="btn btn-primary btn-xs" aw-tool-tip="Cancel" data-placement="top"><i class="fa fa-minus-circle"></i></a>
|
||||
<a href="" ng-click="deleteJob()" id="delete-job-button" ng-hide="job_status.status == 'running' || job_status.status == 'pending' " type="button" class="btn btn-primary btn-xs" aw-tool-tip="Delete" data-placement="top"><i class="fa fa-trash-o"></i></a>
|
||||
<a href="" ng-click="relaunchJob()" id="relaunch-job-button" type="button" class="btn btn-primary btn-xs" aw-tool-tip="Relaunch using the same parameters" data-placement="top"><i class="fa fa-rocket"></i></a>
|
||||
<button type="button" id="summary-button" class="btn btn-primary btn-xs" ng-click="toggleSummary()" aw-tool-tip="View summary" data-placement="top"><i class="fa fa-arrow-circle-left"></i></button>
|
||||
</div>
|
||||
|
||||
@ -3,4 +3,12 @@
|
||||
<div ng-include="'/static/partials/schedule_dialog.html'"></div>
|
||||
<div ng-include="'/static/partials/logviewer.html'"></div>
|
||||
<div id="survey-modal-dialog"></div>
|
||||
|
||||
<div id="copy-job-modal" style="display:none">
|
||||
<form name="copy_form" id="copy_form">
|
||||
What would you like to name the copy of job template <b><span id=job_name></span></b>?<br>
|
||||
<input id="new_copy_name" name="new_copy_name" ng-model ="new_copy_name" ng-required="true" class="form-control ng-pristine ng-invalid-required ng-invalid" style="margin-top:10px;">
|
||||
<div class="error survey_error ng-hide" ng-show="copy_form.new_copy_name.$dirty && copy_form.new_copy_name.$error.required">A value is required!</div></input>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
Loading…
x
Reference in New Issue
Block a user