diff --git a/awx/api/views.py b/awx/api/views.py index 051134389e..495faa94df 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -1768,6 +1768,12 @@ class SystemJobTemplateSchedulesList(SubListCreateAPIView): relationship = 'schedules' parent_key = 'unified_job_template' + def post(self, request, *args, **kwargs): + system_job = self.get_parent_object() + if system_job.schedules.count() > 0: + return Response({"error": "Multiple schedules for Systems Jobs is not allowed"}, status=status.HTTP_400_BAD_REQUEST) + return super(SystemJobTemplateSchedulesList, self).post(request, *args, **kwargs) + class SystemJobTemplateJobsList(SubListAPIView): model = SystemJob diff --git a/awx/main/migrations/0059_v210_changes.py b/awx/main/migrations/0059_v210_changes.py index 016e08a9fe..89d12fa334 100644 --- a/awx/main/migrations/0059_v210_changes.py +++ b/awx/main/migrations/0059_v210_changes.py @@ -9,18 +9,18 @@ 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", + SystemJobTemplate(name='Cleanup Job Details', + description="Remove job history older than X 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", + description="Remove deleted object history older than X 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", + description="Remove activity stream history older than X days", job_type="cleanup_activitystream", created=now(), modified=now()).save() diff --git a/awx/plugins/inventory/ec2.ini.example b/awx/plugins/inventory/ec2.ini.example index a0c8672394..c66bf309b1 100644 --- a/awx/plugins/inventory/ec2.ini.example +++ b/awx/plugins/inventory/ec2.ini.example @@ -73,3 +73,23 @@ nested_groups = False # If you want to exclude any hosts that match a certain regular expression # pattern_exclude = stage-* + +# Instance filters can be used to control which instances are retrieved for +# inventory. For the full list of possible filters, please read the EC2 API +# docs: http://docs.aws.amazon.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeInstances.html#query-DescribeInstances-filters +# Filters are key/value pairs separated by '=', to list multiple filters use +# a list separated by commas. See examples below. + +# Retrieve only instances with (key=value) env=stage tag +# instance_filters = tag:env=stage + +# Retrieve only instances with role=webservers OR role=dbservers tag +# instance_filters = tag:role=webservers,tag:role=dbservers + +# Retrieve only t1.micro instances OR instances with tag env=stage +# instance_filters = instance-type=t1.micro,tag:env=stage + +# You can use wildcards in filter values also. Below will list instances which +# tag Name value matches webservers1* +# (ex. webservers15, webservers1a, webservers123 etc) +# instance_filters = tag:Name=webservers1* diff --git a/awx/plugins/inventory/ec2.py b/awx/plugins/inventory/ec2.py index c8e6d6e7f3..aec6473be6 100755 --- a/awx/plugins/inventory/ec2.py +++ b/awx/plugins/inventory/ec2.py @@ -123,6 +123,7 @@ from boto import ec2 from boto import rds from boto import route53 import ConfigParser +from collections import defaultdict try: import json @@ -257,6 +258,8 @@ class Ec2Inventory(object): pattern_include = config.get('ec2', 'pattern_include') if pattern_include and len(pattern_include) > 0: self.pattern_include = re.compile(pattern_include) + else: + self.pattern_include = None except ConfigParser.NoOptionError, e: self.pattern_include = None @@ -265,8 +268,17 @@ class Ec2Inventory(object): pattern_exclude = config.get('ec2', 'pattern_exclude'); if pattern_exclude and len(pattern_exclude) > 0: self.pattern_exclude = re.compile(pattern_exclude) + else: + self.pattern_exclude = None except ConfigParser.NoOptionError, e: - self.pattern_exclude = '' + self.pattern_exclude = None + + # Instance filters (see boto and EC2 API docs) + self.ec2_instance_filters = defaultdict(list) + if config.has_option('ec2', 'instance_filters'): + for x in config.get('ec2', 'instance_filters', '').split(','): + filter_key, filter_value = x.split('=') + self.ec2_instance_filters[filter_key].append(filter_value) def parse_cli_args(self): ''' Command line argument processing ''' @@ -312,7 +324,13 @@ class Ec2Inventory(object): print("region name: %s likely not supported, or AWS is down. connection to region failed." % region) sys.exit(1) - reservations = conn.get_all_instances() + reservations = [] + if self.ec2_instance_filters: + for filter_key, filter_values in self.ec2_instance_filters.iteritems(): + reservations.extend(conn.get_all_instances(filters = { filter_key : filter_values })) + else: + reservations = conn.get_all_instances() + for reservation in reservations: for instance in reservation.instances: self.add_instance(instance, region) diff --git a/awx/wsgi.py b/awx/wsgi.py index f7e84dbbf6..6baa09a2f6 100644 --- a/awx/wsgi.py +++ b/awx/wsgi.py @@ -14,6 +14,20 @@ https://docs.djangoproject.com/en/dev/howto/deployment/wsgi/ from awx import prepare_env prepare_env() +import os +import logging +from django.conf import settings +from awx import __version__ as tower_version +logger = logging.getLogger('awx.main.models.jobs') +try: + fd = open("/var/lib/awx/.tower_version", "r") + if fd.read().strip() != tower_version: + logger.error("Tower Versions don't match, potential invalid setup detected") + raise Exception("Tower Versions don't match, potential invalid setup detected") +except Exception: + logger.error("Missing tower version metadata at /var/lib/awx/.tower_version") + raise Exception("Missing tower version metadata at /var/lib/awx/.tower_version") + # Return the default Django WSGI application. from django.core.wsgi import get_wsgi_application application = get_wsgi_application()