From bd5d3778f64663beab8e5e91bcc2734fd54ada57 Mon Sep 17 00:00:00 2001 From: Luke Sneeringer Date: Tue, 5 May 2015 15:33:24 -0500 Subject: [PATCH 1/4] MongoDB installation as part of Tower. --- awx/api/management/__init__.py | 0 awx/api/management/commands/__init__.py | 0 awx/api/management/commands/uses_mongo.py | 40 +++++++++++++++++++++++ awx/api/views.py | 12 +++++++ tools/scripts/ansible-tower | 11 ++++++- 5 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 awx/api/management/__init__.py create mode 100644 awx/api/management/commands/__init__.py create mode 100644 awx/api/management/commands/uses_mongo.py diff --git a/awx/api/management/__init__.py b/awx/api/management/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/awx/api/management/commands/__init__.py b/awx/api/management/commands/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/awx/api/management/commands/uses_mongo.py b/awx/api/management/commands/uses_mongo.py new file mode 100644 index 0000000000..e7d8c611d2 --- /dev/null +++ b/awx/api/management/commands/uses_mongo.py @@ -0,0 +1,40 @@ +# Copyright (c) 2015 Ansible, Inc. +# All Rights Reserved + +import sys + +from django.core.management.base import BaseCommand + +from awx.main.task_engine import TaskSerializer + + +class Command(BaseCommand): + """Return a exit status of 0 if MongoDB should be active, and an + exit status of 1 otherwise. + + This script is intended to be used by bash and init scripts to + conditionally start MongoDB, so its focus is on being bash-friendly. + """ + def handle(self, **kwargs): + # Get the license data. + license_reader = TaskSerializer() + license_data = license_reader.from_file() + + # Does the license contain the system tracking feature? + # If and only if it does, MongoDB should run. + system_tracking = license_data['features']['system_tracking'] + + # Okay, do we need MongoDB to be turned on? + # This is a silly variable assignment right now, but I expect the + # rules here will grow more complicated over time. + # FIXME: Most likely this should be False if HA is active + # (not just enabled by license, but actually in use). + uses_mongo = system_tracking + + # If we do not need Mongo, return a non-zero exit status. + print('MongoDB NOT required') + sys.exit(1) + + # We do need Mongo, return zero. + print('MongoDB required') + sys.exit(0) diff --git a/awx/api/views.py b/awx/api/views.py index 5c177dbebf..00829c5611 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -8,6 +8,7 @@ import datetime import dateutil import time import socket +import subprocess import sys # Django @@ -228,10 +229,21 @@ class ApiV1ConfigView(APIView): except Exception: # FIX: Log return Response({"error": "Invalid License"}, status=status.HTTP_400_BAD_REQUEST) + + # If the license is valid, write it to disk. if license_data['valid_key']: fh = open(TASK_FILE, "w") fh.write(data_actual) fh.close() + + # Spawn a task to ensure that MongoDB is started (or stopped) + # as appropriate, based on whether the license uses it. + if license_data['features']['system_tracking']: + subprocess.call('sudo service mongod start', shell=True) + else: + subprocess.call('sudo service mongod stop', shell=True) + + # Done; return the response. return Response(license_data) return Response({"error": "Invalid license"}, status=status.HTTP_400_BAD_REQUEST) diff --git a/tools/scripts/ansible-tower b/tools/scripts/ansible-tower index 3e3eb86991..29ae269238 100755 --- a/tools/scripts/ansible-tower +++ b/tools/scripts/ansible-tower @@ -27,7 +27,16 @@ fi [ -e "${TOWER_CONFIG}" ] && . "${TOWER_CONFIG}" service_action() { - for svc in ${TOWER_SERVICES}; do + SERVICES=$TOWER_SERVICES + + # Should MongoDB be managed by this script? + # We only manage MongoDB if the license uses it. + tower-manage uses_mongo > /dev/null 2> /dev/null + if [ $? == 0 ]; then + SERVICES="$SERVICES mongod" + fi + + for svc in ${SERVICES}; do service ${svc} $1 this_return=$? if [ $this_return -gt $worst_return ]; then From 158e11dc1c11e606621a729b3b220cecf5ca700a Mon Sep 17 00:00:00 2001 From: Luke Sneeringer Date: Fri, 15 May 2015 15:13:24 -0500 Subject: [PATCH 2/4] Set noqa to silence flake8. --- awx/api/management/commands/uses_mongo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awx/api/management/commands/uses_mongo.py b/awx/api/management/commands/uses_mongo.py index e7d8c611d2..7b9bda26a6 100644 --- a/awx/api/management/commands/uses_mongo.py +++ b/awx/api/management/commands/uses_mongo.py @@ -29,7 +29,7 @@ class Command(BaseCommand): # rules here will grow more complicated over time. # FIXME: Most likely this should be False if HA is active # (not just enabled by license, but actually in use). - uses_mongo = system_tracking + uses_mongo = system_tracking # noqa # If we do not need Mongo, return a non-zero exit status. print('MongoDB NOT required') From 90410aa4b514452089530b1c510efaf3777a034d Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Mon, 18 May 2015 17:07:18 -0400 Subject: [PATCH 3/4] removing resize behavior from inventory manage page --- awx/ui/static/js/controllers/Inventories.js | 38 ++++--- awx/ui/static/js/helpers/Groups.js | 7 +- awx/ui/static/js/helpers/Hosts.js | 10 +- awx/ui/static/js/helpers/Jobs.js | 4 +- awx/ui/static/js/helpers/inventory.js | 104 +------------------- awx/ui/static/js/lists/InventoryHosts.js | 4 +- 6 files changed, 27 insertions(+), 140 deletions(-) diff --git a/awx/ui/static/js/controllers/Inventories.js b/awx/ui/static/js/controllers/Inventories.js index 9c56d8bc03..8e2a42bde3 100644 --- a/awx/ui/static/js/controllers/Inventories.js +++ b/awx/ui/static/js/controllers/Inventories.js @@ -848,8 +848,7 @@ export function InventoriesManage ($log, $scope, $rootScope, $location, GetHostsStatusMsg, GroupsEdit, InventoryUpdate, GroupsCancelUpdate, ViewUpdateStatus, GroupsDelete, Store, HostsEdit, HostsDelete, EditInventoryProperties, ToggleHostEnabled, Stream, ShowJobSummary, - InventoryGroupsHelp, HelpDialog, ViewJob, WatchInventoryWindowResize, - GetHostContainerRows, GetGroupContainerRows, GetGroupContainerHeight, + InventoryGroupsHelp, HelpDialog, ViewJob, GroupsCopy, HostsCopy, Socket) { var PreviousSearchParams, @@ -1000,14 +999,7 @@ export function InventoriesManage ($log, $scope, $rootScope, $location, scope: $scope }); - if ($(window).width() > 1210) { - $scope.initial_height = GetGroupContainerHeight(); - $('#groups-container .list-table-container').height($scope.initial_height); - rows = GetGroupContainerRows(); - } - else { - rows = 20; - } + rows = 20; hostScope.host_page_size = rows; $scope.group_page_size = rows; @@ -1022,8 +1014,20 @@ export function InventoriesManage ($log, $scope, $rootScope, $location, }); // Load data - SearchInit({ scope: $scope, set: 'groups', list: InventoryGroups, url: $scope.inventory.related.root_groups }); - PaginateInit({ scope: $scope, list: InventoryGroups , url: $scope.inventory.related.root_groups, pageSize: rows }); + SearchInit({ + scope: $scope, + set: 'groups', + list: InventoryGroups, + url: $scope.inventory.related.root_groups + }); + + PaginateInit({ + scope: $scope, + list: InventoryGroups , + url: $scope.inventory.related.root_groups, + pageSize: rows + }); + $scope.search(InventoryGroups.iterator, null, true); $scope.$emit('WatchUpdateStatus'); // init socket io conneciton and start watching for status updates @@ -1071,12 +1075,6 @@ export function InventoriesManage ($log, $scope, $rootScope, $location, else { Wait('stop'); } - - WatchInventoryWindowResize({ - group_scope: $scope, - host_scope: hostScope - }); - } }); @@ -1454,8 +1452,6 @@ InventoriesManage.$inject = ['$log', '$scope', '$rootScope', '$location', 'GroupsEdit', 'InventoryUpdate', 'GroupsCancelUpdate', 'ViewUpdateStatus', 'GroupsDelete', 'Store', 'HostsEdit', 'HostsDelete', 'EditInventoryProperties', 'ToggleHostEnabled', 'Stream', 'ShowJobSummary', - 'InventoryGroupsHelp', 'HelpDialog', 'ViewJob', - 'WatchInventoryWindowResize', 'GetHostContainerRows', - 'GetGroupContainerRows', 'GetGroupContainerHeight', 'GroupsCopy', + 'InventoryGroupsHelp', 'HelpDialog', 'ViewJob', 'GroupsCopy', 'HostsCopy', 'Socket' ]; diff --git a/awx/ui/static/js/helpers/Groups.js b/awx/ui/static/js/helpers/Groups.js index 92371a42ec..aa4cd1f0cc 100644 --- a/awx/ui/static/js/helpers/Groups.js +++ b/awx/ui/static/js/helpers/Groups.js @@ -707,11 +707,11 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name */ .factory('GroupsEdit', ['$rootScope', '$location', '$log', '$routeParams', '$compile', 'Rest', 'Alert', 'GroupForm', 'GenerateForm', 'Prompt', 'ProcessErrors', 'GetBasePath', 'SetNodeName', 'ParseTypeChange', 'GetSourceTypeOptions', 'InventoryUpdate', - 'LookUpInit', 'Empty', 'Wait', 'GetChoices', 'UpdateGroup', 'SourceChange', 'Find', 'WatchInventoryWindowResize', + 'LookUpInit', 'Empty', 'Wait', 'GetChoices', 'UpdateGroup', 'SourceChange', 'Find', 'ParseVariableString', 'ToJSON', 'GroupsScheduleListInit', 'SourceForm', 'SetSchedulesInnerDialogSize', 'CreateSelect2', function ($rootScope, $location, $log, $routeParams, $compile, Rest, Alert, GroupForm, GenerateForm, Prompt, ProcessErrors, GetBasePath, SetNodeName, ParseTypeChange, GetSourceTypeOptions, InventoryUpdate, LookUpInit, Empty, Wait, - GetChoices, UpdateGroup, SourceChange, Find, WatchInventoryWindowResize, ParseVariableString, ToJSON, GroupsScheduleListInit, + GetChoices, UpdateGroup, SourceChange, Find, ParseVariableString, ToJSON, GroupsScheduleListInit, SourceForm, SetSchedulesInnerDialogSize, CreateSelect2) { return function (params) { @@ -1230,7 +1230,7 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name parent_scope.removeAddTreeRefreshed = parent_scope.$on('GroupTreeRefreshed', function() { // Clean up Wait('stop'); - WatchInventoryWindowResize(); + if (modal_scope.searchCleanUp) { modal_scope.searchCleanup(); } @@ -2124,7 +2124,6 @@ angular.module('GroupsHelper', [ 'RestServices', 'Utilities', listGenerator.name }); $('#status-modal-dialog').dialog('destroy'); $('#inventory-modal-container').empty(); - //WatchInventoryWindowResize(); }, open: function () { Wait('stop'); diff --git a/awx/ui/static/js/helpers/Hosts.js b/awx/ui/static/js/helpers/Hosts.js index ff6636c33a..0d531262f9 100644 --- a/awx/ui/static/js/helpers/Hosts.js +++ b/awx/ui/static/js/helpers/Hosts.js @@ -173,9 +173,9 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', listGenerator.name, }]) .factory('HostsReload', [ '$routeParams', 'Empty', 'InventoryHosts', 'GetBasePath', 'SearchInit', 'PaginateInit', 'Wait', - 'SetHostStatus', 'SetStatus', 'ApplyEllipsis', 'SetContainerHeights', 'GetHostContainerRows', + 'SetHostStatus', 'SetStatus', 'ApplyEllipsis', function($routeParams, Empty, InventoryHosts, GetBasePath, SearchInit, PaginateInit, Wait, SetHostStatus, SetStatus, - ApplyEllipsis, SetContainerHeights) { + ApplyEllipsis) { return function(params) { var scope = params.scope, @@ -208,9 +208,6 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', listGenerator.name, } }); - // Size containers based on viewport - SetContainerHeights({ scope: scope, reloadHosts: false }); - SearchInit({ scope: scope, set: 'hosts', list: list, url: url }); PaginateInit({ scope: scope, list: list, url: url, pageSize: pageSize }); @@ -408,7 +405,6 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', listGenerator.name, inventory_id: parent_scope.inventory_id }); - //WatchInventoryWindowResize(); }); // Save @@ -446,7 +442,7 @@ angular.module('HostsHelper', [ 'RestServices', 'Utilities', listGenerator.name, }; scope.cancelModal = function() { - // WatchInventoryWindowResize(); + }; }; diff --git a/awx/ui/static/js/helpers/Jobs.js b/awx/ui/static/js/helpers/Jobs.js index c95d593569..591a2bda1b 100644 --- a/awx/ui/static/js/helpers/Jobs.js +++ b/awx/ui/static/js/helpers/Jobs.js @@ -181,8 +181,7 @@ export default ]) .factory('ShowJobSummary', ['Rest', 'Wait', 'GetBasePath', 'FormatDate', 'ProcessErrors', 'GenerateForm', 'JobSummary', - 'WatchInventoryWindowResize', - function (Rest, Wait, GetBasePath, FormatDate, ProcessErrors, GenerateForm, JobSummary, WatchInventoryWindowResize) { + function (Rest, Wait, GetBasePath, FormatDate, ProcessErrors, GenerateForm, JobSummary) { return function (params) { // Display status info in a modal dialog- called from inventory edit page @@ -261,7 +260,6 @@ export default }); $('#status-modal-dialog').dialog('destroy'); $('#inventory-modal-container').empty(); - WatchInventoryWindowResize(); }, open: function () { Wait('stop'); diff --git a/awx/ui/static/js/helpers/inventory.js b/awx/ui/static/js/helpers/inventory.js index 18dd2b4afa..04be9a966b 100644 --- a/awx/ui/static/js/helpers/inventory.js +++ b/awx/ui/static/js/helpers/inventory.js @@ -17,109 +17,7 @@ export default angular.module('InventoryHelper', ['RestServices', 'Utilities', 'OrganizationListDefinition', listGenerator.name, 'AuthService', 'InventoryHelper', 'InventoryFormDefinition', 'ParseHelper', 'SearchHelper', 'VariablesHelper', ]) - - .factory('GetGroupContainerHeight', [ function() { - return function() { - - /*console.log('window height: ' + $(window).height()); - console.log('main-menu: ' + $('.main-menu').outerHeight()); - console.log('main_tabs: ' + $('#main_tabs').outerHeight()); - console.log('breadcrumbs: ' + $('#breadcrumbs').outerHeight()); - console.log('footer: ' + $('.site-footer').outerHeight()); - console.log('group-breadcrumbs: ' + $('.group-breadcrumbs').outerHeight()); - console.log('searchwidget: ' + $('#groups-container #search-widget-container').outerHeight()); - console.log('group table head: ' + $('#groups_table thead').height()); - console.log('subtotal: ' + ( $(window).height() - $('.main-menu').outerHeight() - $('#main_tabs').outerHeight() - $('#breadcrumbs').outerHeight() - - $('.site-footer').outerHeight() - $('.group-breadcrumbs').outerHeight() - $('#groups-container #search-widget-container').outerHeight() - - $('#groups_table thead').height() )); - */ - var height = $(window).height() - $('#main-menu-container .navbar').outerHeight() - $('#breadcrumbs').outerHeight() - - $('.site-footer').outerHeight() - $('.group-breadcrumbs').outerHeight() - $('#groups-container #search-widget-container').outerHeight() - - $('#groups_table thead').height() - 90; - height = (height < 600) ? 600 : height; - return height; - }; - }]) - - .factory('GetHostContainerRows', [ function() { - return function() { - var height, rows; - height = $('#hosts-container .list-well').height() - $('#hosts-constainer .list-well .row').height() - $('#hosts_table thead').height(); - rows = Math.floor(height / 44) - 2; - // rows = (rows < 20) ? 20 : rows; - return rows; - }; - }]) - - .factory('GetGroupContainerRows', [ function() { - return function() { - var height, rows; - height = $('#groups-container .list-table-container').height(); - rows = Math.floor(height / 44) - 2; - // rows = (rows < 20) ? 20 : rows; - return rows; - }; - }]) - - .factory('SetContainerHeights', [ 'GetGroupContainerHeight', 'GetHostContainerRows', function(GetGroupContainerHeight, GetHostContainerRows) { - return function(params) { - var group_scope = params.group_scope, - host_scope = params.host_scope, - reloadHosts = (params.reloadHosts) ? true : false, - height, rows; - - $('#groups-container .list-table-container').height('auto'); - $('#hosts-container .list-well').height('auto'); - $('#hosts-container .list-table-container').height('auto'); - - setTimeout(function() { - if ($(window).width() > 1210) { - height = GetGroupContainerHeight(); - $('#groups-container .list-table-container').height(height); - $('#hosts-container .list-table-container').height(height); - setTimeout(function() { $('#hosts-container .list-well').height( $('#groups-container .list-well').outerHeight()); }, 500); - } - - if (reloadHosts) { - // we need ro recalc the the page size - if ($(window).width() > 1210) { - rows = GetHostContainerRows(); - host_scope.host_page_size = rows; - group_scope.group_page_size = rows; - } - else { - // on small screens we go back to the default - host_scope.host_page_size = 20; - group_scope.group_page_size = 20; - } - host_scope.changePageSize('hosts', 'host'); - group_scope.changePageSize('groups', 'group'); - } - }, 100); - - }; - }]) - - .factory('WatchInventoryWindowResize', ['ApplyEllipsis', 'SetContainerHeights', - function (ApplyEllipsis, SetContainerHeights) { - return function (params) { - // Call to set or restore window resize - var group_scope = params.group_scope, - host_scope = params.host_scope; - $(window).off("resize"); - $(window).resize(_.debounce(function() { - ApplyEllipsis('#groups_table .group-name a'); - ApplyEllipsis('#hosts_table .host-name a'); - SetContainerHeights({ - group_scope: group_scope, - host_scope: host_scope, - reloadHosts: true - }); - }, 500)); - }; - } - ]) - + .factory('SaveInventory', ['InventoryForm', 'Rest', 'Alert', 'ProcessErrors', 'LookUpInit', 'OrganizationList', 'GetBasePath', 'ParseTypeChange', 'Wait', 'ToJSON', function (InventoryForm, Rest, Alert, ProcessErrors, LookUpInit, OrganizationList, GetBasePath, ParseTypeChange, Wait, diff --git a/awx/ui/static/js/lists/InventoryHosts.js b/awx/ui/static/js/lists/InventoryHosts.js index bbc3ba4c31..8ba770faa2 100644 --- a/awx/ui/static/js/lists/InventoryHosts.js +++ b/awx/ui/static/js/lists/InventoryHosts.js @@ -30,7 +30,7 @@ export default label: 'Hosts', ngClick: "editHost(host.id)", ngClass: "{ 'host-disabled-label': !host.enabled }", - columnClass: 'col-lg-6 col-md-9 col-sm-9 col-xs-7', + columnClass: 'col-lg-6 col-md-8 col-sm-8 col-xs-7', dataHostId: "{{ host.id }}", dataType: "host" }, @@ -52,7 +52,7 @@ export default fieldActions: { - columnClass: 'col-lg-6 col-md-3 col-sm-3 col-xs-5 text-right', + columnClass: 'col-lg-6 col-md-4 col-sm-4 col-xs-5 text-right', label: false, active_failures: { From 71fc2320d0459b9e19dcf2dde29efbcd55b2866c Mon Sep 17 00:00:00 2001 From: Luke Sneeringer Date: Tue, 19 May 2015 16:17:54 -0400 Subject: [PATCH 4/4] System tracking is off if there is no license. --- awx/api/management/commands/uses_mongo.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/awx/api/management/commands/uses_mongo.py b/awx/api/management/commands/uses_mongo.py index 7b9bda26a6..430e354f3c 100644 --- a/awx/api/management/commands/uses_mongo.py +++ b/awx/api/management/commands/uses_mongo.py @@ -20,6 +20,11 @@ class Command(BaseCommand): license_reader = TaskSerializer() license_data = license_reader.from_file() + # Does the license have features, at all? + # If there is no license yet, then all features are clearly off. + if 'features' not in license_data: + return False + # Does the license contain the system tracking feature? # If and only if it does, MongoDB should run. system_tracking = license_data['features']['system_tracking']