diff options
Diffstat (limited to 'django/engagementmanager/vm_integration')
-rwxr-xr-x | django/engagementmanager/vm_integration/__init__.py | 38 | ||||
-rwxr-xr-x | django/engagementmanager/vm_integration/em_api.py | 188 | ||||
-rwxr-xr-x | django/engagementmanager/vm_integration/vm_client.py | 152 |
3 files changed, 378 insertions, 0 deletions
diff --git a/django/engagementmanager/vm_integration/__init__.py b/django/engagementmanager/vm_integration/__init__.py new file mode 100755 index 0000000..1726c13 --- /dev/null +++ b/django/engagementmanager/vm_integration/__init__.py @@ -0,0 +1,38 @@ +# +# ============LICENSE_START========================================== +# org.onap.vvp/engagementmgr +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. diff --git a/django/engagementmanager/vm_integration/em_api.py b/django/engagementmanager/vm_integration/em_api.py new file mode 100755 index 0000000..b41a3ff --- /dev/null +++ b/django/engagementmanager/vm_integration/em_api.py @@ -0,0 +1,188 @@ +# +# ============LICENSE_START========================================== +# org.onap.vvp/engagementmgr +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +import json +from django.core.exceptions import ObjectDoesNotExist +from engagementmanager.slack_client.api import SlackClient +from engagementmanager.models import Checklist, VF +from engagementmanager.service.checklist_service import CheckListSvc +from engagementmanager.service.checklist_state_service import set_state +from engagementmanager.utils import dict_path_get +from engagementmanager.utils.constants import CheckListCategory, CheckListState, EngagementStage +from engagementmanager.utils.request_data_mgr import request_data_mgr +from engagementmanager.service.logging_service import LoggingServiceFactory + +logger = LoggingServiceFactory.get_logger() + + +def test_finished_callback(checklist_test_results): + logger.debug( + "test_finished_callback has signaled that a test has finished with test results %r", checklist_test_results) + + if not checklist_test_results: + msg = "Couldn't find payload argument inside kwargs array, aborting signal" + logger.error(msg) + raise KeyError(msg) + + checklist_test_results['description'] = "Validation manager has indicated that checklist {} tests has been completed with results".format( + checklist_test_results['checklist_uuid']) + + checklist = Checklist.objects.get( + uuid=checklist_test_results['checklist_uuid']) + request_data_mgr.set_cl_uuid(checklist.uuid) + data = CheckListSvc().setChecklistDecisionsFromValMgr( + user=checklist.owner, + checklist_uuid=checklist_test_results['checklist_uuid'], + decisions=checklist_test_results['decisions'], + checklist_results_from_jenkins=checklist_test_results + ) + return data + + +def git_push_callback(gitlab_data): + """ + When we are notified that a repo has received a push, we must reject any checklists not in the + closed or archived state whose associated files have been modified. + """ + logger.debug("Validation manager has signaled that a git push has occurred") + msg = "OK" + data = None + + # sanity check provided arguments + for key in ['project', 'project/git_ssh_url', 'commits']: + if not dict_path_get(gitlab_data, key): + msg = "{!r} in the git_push signal gitlab_data is missing or empty.".format( + key) + logger.error(msg) + raise KeyError(msg) + + # For now, ignore pushes made to any branch other than 'master'. + if gitlab_data['ref'] != u'refs/heads/master': + logger.warn("A non-master ref %r was updated. Ignoring.", + gitlab_data['ref']) + return None + + # sanity check payload data + if int(gitlab_data['total_commits_count']) == 0: + logger.debug("total_commits_count = %s", + gitlab_data['total_commits_count']) + msg = "Something is wrong: Number of commits is 0 even after a push event has been invoked from validation manager to engagement manager" + logger.warn(msg) + raise ValueError(msg) + + if gitlab_data['before'] == '0000000000000000000000000000000000000000': + logger.debug('This is the first commit pushed to master.') + + git_ssh_url = gitlab_data['project']['git_ssh_url'] + + vf = VF.objects.filter(git_repo_url=git_ssh_url) + + if len(vf) == 0: + msg = "Couldn't fetch any VF" + logger.error(msg) + raise ObjectDoesNotExist(msg) + else: + vf = VF.objects.get(git_repo_url=git_ssh_url) + + checklists = (Checklist.objects + .filter(engagement=vf.engagement) + # @UndefinedVariable + .exclude(state=CheckListState.archive.name) + .exclude(state=CheckListState.closed.name)) # @UndefinedVariable + + committed_files = set(file + for commit in gitlab_data['commits'] + for status in ['added', 'modified', 'removed'] + for file in commit[status]) + logger.debug("Committed files list: [%s]" % ', '.join(committed_files)) + + # send notifications to reviewers and peer reviewers when the git repo is + # updated + vf_name = vf.name + engagement_manual_id = vf.engagement.engagement_manual_id + reviewer = vf.engagement.reviewer + peer_reviewer = vf.engagement.peer_reviewer + slack_client = SlackClient() + slack_client.send_notifications_on_git_push( + engagement_manual_id, vf_name, reviewer, peer_reviewer, committed_files) + + # loop through the checklists and start automation if necessary + for checklist in checklists: + user = checklist.owner + template_category = checklist.template.category + mutual_files = committed_files.intersection( + json.loads(checklist.associated_files)) + logger.debug("Mutual files list for checklist %s: [%s]" % ( + checklist.uuid, ', '.join(committed_files))) + if not mutual_files and\ + template_category == CheckListCategory.heat.name and\ + not any(file + for file in committed_files + for extension in ['.yaml', '.yml', '.env'] + if file.lower().endswith(extension)): + continue + if checklist.state == CheckListState.pending.name: # @UndefinedVariable + description = "Checklist {checklist.name} (part of VF {vf.name}/{vf.uuid}) in Pending state will transition to Automation due to a push action on files [{mutual_files}]. chosen EL: {user.full_name}".format( + checklist=checklist, + vf=vf, + mutual_files=", ".join(mutual_files), + user=user, + ) + else: + description = "Checklist {checklist.uuid} (part of VF {vf.name}/{vf.uuid}) has been rejected due to a push action made on files [{mutual_files}]. chosen EL is: {user.full_name}".format( + checklist=checklist, + vf=vf, + mutual_files=", ".join(mutual_files), + user=user, + ) + logger.debug(description) + # FIXME Setting parameters into a global before calling a function that will break without + # them is TERRIBLE. We must fix this before we open-source this code. + request_data_mgr.set_cl_uuid(checklist.uuid) + request_data_mgr.set_user(user) + data = set_state( # means that the checklist will be declined and a cloned one is + # created in PENDING status + decline=True, + checklist_uuid=checklist.uuid, + # means the checklist will be triggered into automation cycle + isMoveToAutomation=True, + description="This change was triggered by an update to the engagement git repository.") + + logger.debug("set_state returned (%r)" % data) + + return data diff --git a/django/engagementmanager/vm_integration/vm_client.py b/django/engagementmanager/vm_integration/vm_client.py new file mode 100755 index 0000000..04d77c5 --- /dev/null +++ b/django/engagementmanager/vm_integration/vm_client.py @@ -0,0 +1,152 @@ +# +# ============LICENSE_START========================================== +# org.onap.vvp/engagementmgr +# =================================================================== +# Copyright © 2017 AT&T Intellectual Property. All rights reserved. +# =================================================================== +# +# Unless otherwise specified, all software contained herein is licensed +# under the Apache License, Version 2.0 (the “License”); +# you may not use this software except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# +# Unless otherwise specified, all documentation contained herein is licensed +# under the Creative Commons License, Attribution 4.0 Intl. (the “License”); +# you may not use this documentation except in compliance with the License. +# You may obtain a copy of the License at +# +# https://creativecommons.org/licenses/by/4.0/ +# +# Unless required by applicable law or agreed to in writing, documentation +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# ============LICENSE_END============================================ +# +# ECOMP is a trademark and service mark of AT&T Intellectual Property. +from django.conf import settings +from django.db.models import Q +from engagementmanager.apps import bus_service +from engagementmanager.bus.messages.activity_event_message import \ + ActivityEventMessage +from engagementmanager.models import VF, Role, IceUserProfile +from engagementmanager.utils.constants import Roles +from engagementmanager.utils.activities_data import \ + VFProvisioningActivityData +import concurrent.futures +import validationmanager.em_integration.vm_api as vm_api +from engagementmanager.service.logging_service import LoggingServiceFactory + +logger = LoggingServiceFactory.get_logger() +executor = concurrent.futures.ThreadPoolExecutor(max_workers=4) + + +def send_jenkins_job_and_gitlab_repo_exists(vf): + # A signal which check if jenkins job was created and also if gitlab repo + logger.debug( + "Sending a call to validation manager. Call=jenkins_job_and_gitlab_repo_exists_callback. vf=%s", vf.uuid) + is_ready = vm_api.jenkins_job_and_gitlab_repo_exists_callback(vf=vf) + return is_ready + + +def send_cl_from_pending_to_automation_event(checkListObj): + # A signal that is sent when Engagement MAnager moves CL from Pending to + # Automation (for example when a CL is rejected by other signal from + # validation manager) + vf = VF.objects.get(engagement=checkListObj.engagement) + logger.debug( + "Sending a call to validation manager. Call=send_cl_from_pending_to_automation_event. checklistUuid=%s", checkListObj.uuid) + vm_api.cl_from_pending_to_automation_callback(vf=vf, checklist=checkListObj) + + +def send_ssh_key_created_or_updated_event(user): + # A signal which is sent from the EM to the VM when a user is adding or + # updating their ssh key + logger.debug( + "Sending a call to validation manager. Call=send_ssh_key_created_or_updated_event. user=%s", user.uuid) + vm_api.ssh_key_created_or_updated_callback(user=user) + +def send_create_user_in_rgwa_event(user): + # A signal which is sent from the EM to the VM when a user is adding or + # updating their ssh key + logger.debug( + "Sending a call to validation manager. Call=send_create_user_in_rgwa_event. user=%s", user.full_name) + vm_api.create_user_rgwa(user=user) + + +def send_remove_all_standard_users_from_project_event(gitlab, project_id, formatted_vf): + logger.debug( + "Sending a call to validation manager. Call=send_remove_all_standard_users_from_project_event.") + vm_api.remove_all_standard_users_from_project( + gitlab, project_id, formatted_vf) + + +def send_get_project_by_vf_event(vf, gitlab): + if not settings.IS_SIGNAL_ENABLED: + return None + logger.debug( + "Sending a call to validation manager. Call=send_get_project_by_vf_event.") + vm_api.get_project_by_vf(vf, gitlab) + + +def send_provision_new_vf_event(vf): + # A signal which is sent from the EM to the VM when a new VF is created. VM will than create a + # gitlab repo for that new VF. + # + # Note: despite its name, this signal is not used only for new vfs, but to update existing gitlab + # and jenkins provisioning when a vf changes e.g. when team members are + # added or removed. + try: + vm_api.provision_new_vf_callback(vf=vf) + logger.debug( + "Sending a call to validation manager. Call=send_provision_new_vf_event. vf=%s", vf.uuid) + except Exception as e: + el_role = Role.objects.get(name=Roles.el.name) # @UndefinedVariable + admin_role = Role.objects.get( + name=Roles.admin.name) # @UndefinedVariable + el_admin_list = IceUserProfile.objects.all().filter( + Q(role=el_role) | Q(role=admin_role)) + activity_data = VFProvisioningActivityData( + vf, el_admin_list, vf.engagement, e) + bus_service.send_message(ActivityEventMessage(activity_data)) + + +def send_get_list_of_repo_files_event(vf): + # A signal which is sent from the EM to the VM when a NextStep is created + # and we need the VF associated files in the git repository + files = vm_api.get_list_of_repo_files_callback(vf=vf) + logger.debug( + "Sending a call to validation manager. Call=send_get_list_of_repo_files_event. vf=%s", vf.uuid) + + formatted_repo_files = [] + + for file in files: + formatted_repo_files.append(file['name']) + logger.debug(file['name']) + + return formatted_repo_files + + +''''''''''''''''''''''''''' + UTIL FUNCTIONS FOR SIGNALS +''''''''''''''''''''''''''' + + +def fire_event_in_bg(function_name, obj): + event_function = globals()[function_name] + logger.debug( + " . . . . . . . . . . . . Fire event in background started: %s . . . . . . . . . . . . ", function_name) + future = executor.submit(event_function, obj) + logger.debug("Main thread continue without blocking...") |