diff --git a/apps/ops/ansible/inventory.py b/apps/ops/ansible/inventory.py index da9e8b599..4f108c13b 100644 --- a/apps/ops/ansible/inventory.py +++ b/apps/ops/ansible/inventory.py @@ -10,7 +10,7 @@ __all__ = ['JMSInventory'] class JMSInventory: def __init__(self, assets, account_policy='privileged_first', - account_prefer='root,Administrator', host_callback=None): + account_prefer='root,Administrator', host_callback=None, exclude_localhost=False): """ :param assets: :param account_prefer: account username name if not set use account_policy @@ -21,6 +21,7 @@ class JMSInventory: self.account_policy = account_policy self.host_callback = host_callback self.exclude_hosts = {} + self.exclude_localhost = exclude_localhost @staticmethod def clean_assets(assets): @@ -207,6 +208,8 @@ class JMSInventory: for host in hosts: name = host.pop('name') data['all']['hosts'][name] = host + if self.exclude_localhost and data['all']['hosts'].__contains__('localhost'): + data['all']['hosts'].update({'localhost': {'ansible_host': '255.255.255.255'}}) return data def write_to_file(self, path): diff --git a/apps/ops/models/job.py b/apps/ops/models/job.py index c0e45529b..d3f669fbc 100644 --- a/apps/ops/models/job.py +++ b/apps/ops/models/job.py @@ -295,10 +295,20 @@ class JobExecution(JMSOrgBaseModel): task_id = current_task.request.root_id self.task_id = task_id + def check_danger_keywords(self): + lines = self.job.playbook.check_dangerous_keywords() + if len(lines) > 0: + for line in lines: + print('\033[31mThe {} line of the file \'{}\' contains the ' + 'dangerous keyword \'{}\'\033[0m'.format(line['line'], line['file'], line['keyword'])) + raise Exception("Playbook contains dangerous keywords") + def start(self, **kwargs): self.date_start = timezone.now() self.set_celery_id() self.save() + if self.job.type == 'playbook': + self.check_danger_keywords() runner = self.get_runner() try: cb = runner.run(**kwargs) diff --git a/apps/ops/models/playbook.py b/apps/ops/models/playbook.py index efcd87730..2bef76741 100644 --- a/apps/ops/models/playbook.py +++ b/apps/ops/models/playbook.py @@ -9,6 +9,13 @@ from ops.const import CreateMethods from ops.exception import PlaybookNoValidEntry from orgs.mixins.models import JMSOrgBaseModel +dangerous_keywords = ( + 'delegate_to:localhost', + 'delegate_to:127.0.0.1', + 'local_action', + 'connection:local', +) + class Playbook(JMSOrgBaseModel): id = models.UUIDField(default=uuid.uuid4, primary_key=True) @@ -20,6 +27,27 @@ class Playbook(JMSOrgBaseModel): verbose_name=_('CreateMethod')) vcs_url = models.CharField(max_length=1024, default='', verbose_name=_('VCS URL'), null=True, blank=True) + def check_dangerous_keywords(self): + result = [] + for root, dirs, files in os.walk(self.work_dir): + for f in files: + if str(f).endswith('.yml') or str(f).endswith('.yaml'): + lines = self.search_keywords(os.path.join(root, f)) + if len(lines) > 0: + for line in lines: + result.append({'file': f, 'line': line[0], 'keyword': line[1]}) + return result + + @staticmethod + def search_keywords(file): + result = [] + with open(file, 'r') as f: + for line_num, line in enumerate(f): + for keyword in dangerous_keywords: + if keyword in line.replace(' ', ''): + result.append((line_num, keyword)) + return result + @property def entry(self): work_dir = self.work_dir diff --git a/apps/ops/serializers/job.py b/apps/ops/serializers/job.py index 13afe6d6c..792a23acd 100644 --- a/apps/ops/serializers/job.py +++ b/apps/ops/serializers/job.py @@ -1,3 +1,5 @@ +import uuid + from django.utils.translation import gettext_lazy as _ from rest_framework import serializers @@ -14,6 +16,14 @@ class JobSerializer(BulkOrgResourceModelSerializer, PeriodTaskSerializerMixin): run_after_save = serializers.BooleanField(label=_("Run after save"), default=False, required=False) nodes = serializers.ListField(required=False, child=serializers.CharField()) date_last_run = serializers.DateTimeField(label=_('Date last run'), read_only=True) + name = serializers.CharField(label=_('Name'), max_length=128, allow_blank=True, required=False) + + def to_internal_value(self, data): + instant = data.get('instant', False) + if instant: + _uid = str(uuid.uuid4()).split('-')[-1] + data['name'] = f'job-{_uid}' + return super().to_internal_value(data) def get_request_user(self): request = self.context.get('request')