1
0
Fork 0
mirror of https://github.com/mmumshad/ansible-playable.git synced 2025-03-09 23:38:54 +00:00

Initial Commit

This commit is contained in:
Mumshad Mannambeth 2017-06-07 13:36:44 -04:00
commit c92f737237
273 changed files with 16964 additions and 0 deletions

View file

@ -0,0 +1,185 @@
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" ng-click="cancel()">&times;</button>
<h4 class="modal-title">Play</h4>
</div>
<div class="modal-body">
<div class="row" id="PlaybookExecutionModal">
<!--<button class="btn btn-default" ng-click="view = (view === 'console' ? 'table' : 'console')">Toggle View</button>-->
<div style="background:black;color:lightgrey;width:100%;padding:20px;" ng-if="result" ng-show="view=='console'">
<p class="logconsole" ng-bind-html="result"></p>
</div>
<!--<div ng-if="ansibleOutputObject" ng-show="view=='table'" style="margin-top:20px;">
&lt;!&ndash;<div class="row" ng-repeat="resultItem in ansibleOutputResult">
<div class="col-md-1"><div class="btn btn-default">{{resultItem.type}}</div></div>
<div class="col-md-5"><div class="btn btn-primary">{{resultItem.name}}</div></div>
<div class="col-md-6"><div class="btn btn-info" ng-if="resultItem.host">{{resultItem.host}}</div></div>
<div class="col-md-offset-1 col-md-2"><div class="btn " ng-class="{'btn-success': resultItem.status == 'ok' || resultItem.status == 'changed', 'btn-danger': resultItem.status == 'fatal', 'btn-warning': resultItem.status == 'skipping'}" ng-if="resultItem.status">Status = {{resultItem.status}}</div></div>
<div class="col-md-3"><div class="btn btn-info" ng-if="resultItem.status_2.trim()">Status2 = {{resultItem.status_2}}</div></div>
<div class="col-md-3"><div class="btn" ng-if="resultItem.resultObject.changed.trim()" ng-class="{'btn-success': resultItem.resultObject.changed == true, 'btn-warning': resultItem.resultObject.changed == false}">Changed = {{resultItem.resultObject.changed}}</div></div>
<div class="col-md-3"><div class="btn" ng-if="resultItem.resultObject.failed" ng-class="{'btn-danger': resultItem.resultObject.failed}">Failed = {{resultItem.resultObject.failed}}</div></div>
<div class="col-md-offset-1 col-md-11" ng-if="resultItem.resultObject.msg" ><p style="background:grey;" class="logconsole">{{resultItem.resultObject.msg}}</p></div>
<div class="col-md-offset-1 col-md-11" ng-if="resultItem.resultObject.formattedStdErr" ><p style="color:#cd616b;" class="logconsole" ng-bind-html="resultItem.resultObject.formattedStdErr"></p></div>
<div class="col-md-offset-1 col-md-11" ng-if="resultItem.resultObject.formattedStdOut" ><p style="color:green;" class="logconsole" ng-bind-html="resultItem.resultObject.formattedStdOut"></p></div>
&lt;!&ndash;<div class="col-md-offset-1 col-md-11"><p class="logconsole">{{resultItem.resultString}}</p></div>&ndash;&gt;
<span class="fa fa-spinner fa-spin" ng-if="AnsiblePlayBookLoading && $last"></span>
</div>&ndash;&gt;
&lt;!&ndash;<div ng-repeat="(host, stats) in ansibleOutputObject.stats">
<span><b>Host : </b>{{host}}</span>
<span class="btn btn-default btn-info">OK <span class="badge">{{stats.ok}}</span></span>
<span class="btn btn-default" ng-class="{'btn-success': stats.changed}" >Changed <span class="badge">{{stats.changed}}</span></span>
<span class="btn btn-default" ng-class="{'btn-warning': stats.skipped}">Skipped <span class="badge">{{stats.skipped}}</span></span>
<span class="btn btn-default" ng-class="{'btn-danger': stats.unreachable}">Unreachable <span class="badge">{{stats.unreachable}}</span></span>
<span class="btn btn-default" ng-class="{'btn-danger': stats.failures}">Failures <span class="badge">{{stats.failures}}</span></span>
</div>&ndash;&gt;
<h3>Run Statistics</h3>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>Host</th>
<th>Ok</th>
<th>Changed</th>
<th>Skipped</th>
<th>Unreachable</th>
<th>Failures</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="(host, stats) in ansibleOutputObject.stats">
<td>{{host}}</td>
<td>{{stats.ok}}</td>
<td><span ng-class="{'label label-success': stats.changed}">{{stats.changed}}</span></td>
<td><span ng-class="{'label label-warning': stats.skipped}">{{stats.skipped}}</span></td>
<td><span ng-class="{'label label-danger': stats.unreachable}">{{stats.unreachable}}</span></td>
<td><span ng-class="{'label label-danger': stats.failures}">{{stats.failures}}</span></td>
</tr>
</tbody>
</table>
</div>
<div class="row" ng-repeat="playObject in ansibleOutputObject.plays">
&lt;!&ndash;<div class="col-md-3"><div class="btn btn-default">Play - {{playObject.play.name}}</div></div>&ndash;&gt;
<div class="col-md-12">
<uib-accordion close-others="false">
<div uib-accordion-group class="panel-default" is-open="true" ng-repeat="taskObject in playObject.tasks">
<uib-accordion-heading>
Play - {{playObject.play.name}} - Tasks - {{taskObject.task.name}}
<span class="fa fa-spinner fa-spin" ng-if="AnsiblePlayBookLoading && $last"></span>
</uib-accordion-heading>
<div class="col-md-12" ng-repeat="(hostName, hostObject) in taskObject.hosts">
<div class="col-md-3"><b>Host :</b> {{hostName}}</div>
<div class="col-md-3"><b>Method :</b> {{hostObject.invocation && hostObject.invocation.module_name}}</div>
<div class="col-md-2"><div class="btn" ng-class="{'btn-success': hostObject.changed == true, 'btn-warning': hostObject.changed == false}" style="padding: 2px 5px">Changed <span class="badge">{{hostObject.changed}}</span></div></div>
<div class="col-md-2" ng-if="hostObject.skipped == true"><div class="btn" ng-class="{'btn-warning': hostObject.skipped == true}" style="padding: 2px 5px">Skipped <span class="badge">{{hostObject.skipped}}</span></div></div>
<div class="col-md-1"><div class="btn btn-default" ng-show="hostObject.module_stderr || hostObject.stdout || hostObject.stderr || hostObject.msg" ng-click="hostObject.showLogs = !hostObject.showLogs" style="padding: 2px 5px">Logs</div></div>
<div class="col-md-1"><div class="btn btn-warning" ng-show="hostObject.warnings.length" ng-click="hostObject.showWarnings = !hostObject.showWarnings" style="padding: 2px 5px">Warnings</div></div>
<div class="col-md-2"><div class="btn btn-danger" ng-show="hostObject.rc && hostObject.rc != 0">Return Code - {{hostObject.rc}}</div></div>
<div ng-show="hostObject.showLogs" class="col-md-12" ng-if="hostObject.stdout" ><p style="color:grey;" class="logconsole" ng-bind-html="hostObject.stdout | replaceLineBreaks"></p></div>
<div ng-show="hostObject.showLogs" class="col-md-12" ng-if="hostObject.msg" ><p style="color:grey;" class="logconsole" ng-bind-html="hostObject.msg | replaceLineBreaks"></p></div>
<div ng-show="hostObject.showLogs" class="col-md-12" ng-if="hostObject.stderr" ><p style="color:#cd616b;" class="logconsole" ng-bind-html="hostObject.stderr | replaceLineBreaks"></p></div>
<div ng-show="hostObject.showLogs" class="col-md-12" ng-if="hostObject.module_stderr" ><p style="color:#cd616b;" class="logconsole" ng-bind-html="hostObject.module_stderr | replaceLineBreaks"></p></div>
<div ng-show="hostObject.showWarnings" class="col-md-12" ng-if="hostObject.warnings.length" ><p style="color:orangered;" class="logconsole" ng-bind-html="hostObject.warnings.join('\n') | replaceLineBreaks"></p></div>
</div>
</div>
</uib-accordion>
</div>
</div>
</div>-->
</div>
<div class="row" ng-if="!readOnly">
<div class="col-md-3">
<div class="input-group">
<span class="input-group-addon" >Inventory Files</span>
<!--<input ng-model="newPlay.hosts" type="text" class="form-control" placeholder="Playbook Name">-->
<select class="form-control" ng-model="selectedInventoryFile.value" ng-options="inventoryFile as inventoryFile for inventoryFile in inventoryFiles" ng-disabled="!inventoryFiles">
</select>
</div>
</div>
<div class="col-md-9">
<btn class="checkbox-inline"><input type="checkbox" ng-true-value="'Check'" ng-false-value="'No_Check'" ng-model="check_mode.value">Check Mode</btn>
<btn class="checkbox-inline"><input type="checkbox" ng-true-value="'verbose'" ng-model="verbose.value">Verbose</btn>
<btn class="checkbox-inline"><input type="checkbox" ng-true-value="'verbose_detail'" ng-model="verbose_detail.value">Verbose Detail</btn>
<btn class="checkbox-inline"><input type="checkbox" ng-model="refreshLog">Refresh Logs</btn>
<btn class="checkbox-inline"><input type="checkbox" ng-model="additional_tags.show">Tags</btn>
<btn class="checkbox-inline"><input type="checkbox" ng-model="additional_tags.vars">Vars</btn>
</div>
<div class="clearfix"></div>
<div class="col-md-6" ng-show="additional_tags.show">
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>Select</th>
<th>Tag</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="tag in all_tags">
<td><input type="checkbox" ng-model="tag.selected">
</td>
<td>{{tag.name}}</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-md-6" ng-show="additional_tags.show">
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>Select</th>
<th>Host</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="host in all_hosts">
<td><input type="checkbox" ng-model="host.selected">
</td>
<td>{{host.name}}</td>
</tr>
</tbody>
</table>
</div>
</div>
<div ng-show="additional_vars.show">
<complex-var members="complexVar" path="'Parent'" type="'object'" input-width="'400px'">
</complex-var>
</div>
</div>
</div>
<div class="alert alert-danger" ng-if="err_msg">{{err_msg}}</div>
<div class="modal-footer">
<button class="btn btn-success" type="button" ng-if="!readOnly" ng-disabled="!selectedInventoryFile.value || !readyForPlay" ng-click="Run()">Play <span class="fa fa-play" ng-if="!AnsiblePlayBookLoading"></span> <span class="fa fa-spinner fa-spin" ng-if="AnsiblePlayBookLoading"></span></button>
<button class="btn btn-default" type="button" ng-click="cancel()">Close</button>
</div>
</div>

View file

@ -0,0 +1,475 @@
'use strict';
const angular = require('angular');
/*@ngInject*/
export function executionController($scope,$sce, $uibModalInstance, $timeout, ansi2html, ansible, tags, selectedProject, selectedPlaybook, selectedPlay, executionType, executionName, readOnly, runData, projectFolder, roleName) {
'ngInject';
$scope.view = 'console';
$scope.selectedInventoryFile = {value:null};
$scope.verbose_detail = {value:null};
$scope.verbose = {value:'verbose'};
$scope.check_mode = {
value: 'No_Check'
};
$scope.additional_tags = {show: false};
$scope.additional_vars = {show: false};
$scope.refreshLog = true;
$scope.all_tags = [];
$scope.all_hosts = [];
$scope.readOnly = readOnly;
$scope.readyForPlay = false;
/**
* Execute Ansible Playbook
*/
$scope.executeAnsiblePlayBook = function(){
$scope.AnsiblePlayBookLoading = true;
var reqBody = {};
//reqBody.inventory_file_contents = inventory_file_contents;
//reqBody.playbook_file_contents = yaml;
//reqBody.tags = tags || [];
reqBody.tags = [];
$scope.all_tags.map(tag => {
if(tag.selected){
if(tag.name)
reqBody.tags.push(tag.name.trim())
}
});
reqBody.limit_to_hosts = [];
$scope.all_hosts.map(host => {
if(host.selected){
if(host.name)
reqBody.limit_to_hosts.push(host.name.trim())
}
});
reqBody.verbose = $scope.verbose_detail.value || $scope.verbose.value;
reqBody.check_mode = $scope.check_mode.value;
reqBody.inventory_file_name = $scope.selectedInventoryFile.value;
if(roleName){
reqBody.inventory_file_name = roleName + '/tests/' + reqBody.inventory_file_name;
}
console.log("Check Mode = " + reqBody.check_mode);
reqBody.selectedPlaybook = selectedPlaybook.playbook;
reqBody.executionType = executionType;
reqBody.executionName = executionName;
reqBody.ansibleEngine = angular.copy(selectedProject.ansibleEngine);
// Override project folder for roles
if(projectFolder)
reqBody.ansibleEngine.projectFolder = projectFolder;
if(selectedPlay && selectedPlay.play)
reqBody.host = selectedPlay.play.hosts;
$scope.result = "Running...";
ansible.executeAnsiblePlayBook(reqBody,function(response){
//$scope.result = $sce.trustAsHtml(ansi2html.toHtml(response.data).replace(/\n/g, "<br>"));
$scope.refreshLog = true;
$scope.executionData = response.data;
setTimeout(function(){
$scope.refreshLogs();
},3000);
}, function(response){
if(response.data)
$scope.result = $sce.trustAsHtml(ansi2html.toHtml(response.data).replace(/\n/g, "<br>"));
$scope.AnsiblePlayBookLoading = false;
console.log("error" + $scope.result)
}, 'PlaybookExecutionModal');
};
/*setTimeout(function(){
$scope.executeAnsiblePlayBook();
},200);*/
/**
* Get logs
*/
$scope.getLogs = function(){
ansible.getLogs($scope.executionData,function(successResponse) {
$scope.result = $sce.trustAsHtml(ansi2html.toHtml(successResponse.data.replace('SCRIPT_FINISHED','')).replace(/\n/g, "<br>"));
if(successResponse.data.indexOf('SCRIPT_FINISHED') > -1){
$scope.refreshLog = false;
$scope.AnsiblePlayBookLoading = false;
}
$scope.processAnsibleOutput(successResponse.data)
});
};
/**
* Refersh Logs
*/
$scope.refreshLogs = function(){
if($scope.logRefreshTimer){
$timeout.cancel( $scope.logRefreshTimer );
}
$scope.getLogs();
$scope.logRefreshTimer = $timeout(
function(){
//$scope.getLogs(tile);
if($scope.refreshLog) {
$scope.refreshLogs();
}
},
10000
);
$scope.$on(
"$destroy",
function( event ) {
$timeout.cancel( $scope.logRefreshTimer );
}
);
};
/**
* Close the modal
*/
$scope.ok = function () {
$uibModalInstance.close(null);
};
/**
* Cancel modal
*/
$scope.cancel = function () {
$uibModalInstance.dismiss('cancel');
};
/**
* Run a random command on the server
* TODO: Remove this later.
* @param command
*/
$scope.runCommand = function(command){
command = command || $scope.command;
ansible.executeCommand( command,
function(response){
$scope.result = $sce.trustAsHtml(ansi2html.toHtml(response.data).replace(/\n/g, "<br>").replace(/ /g,"&nbsp;"));
}, function(response){
$scope.result = $sce.trustAsHtml(ansi2html.toHtml(response.data).replace(/\n/g, "<br>"));
})
};
/**
* Run Ansible Playbook
* @constructor
*/
$scope.Run = function(){
$scope.executeAnsiblePlayBook();
};
/**
* This is used when viewing the logs from the Runs view
*/
if($scope.readOnly){
$scope.executionData = runData;
$scope.refreshLog = true;
$scope.refreshLogs()
}
/**
* Get List of inventory files
*/
$scope.listOfInventoryFiles = function(){
var rolesTestFolder = null;
if(roleName){
rolesTestFolder = projectFolder + '/' + roleName + '/tests'
}
ansible.getInventoryList(function(response){
$scope.inventoryFiles = response.data;
if($scope.inventoryFiles.length)
$scope.selectedInventoryFile = {value:$scope.inventoryFiles[0]};
/**
* Run Get Tags
*/
if(!readOnly)
$scope.getTags();
},
function(response){
/*$scope.err_msg = response.data;*/
$scope.result = $sce.trustAsHtml(ansi2html.toHtml(response.data).replace(/\n/g, "<br>"));
$scope.view = 'console'
},rolesTestFolder)
};
$scope.listOfInventoryFiles();
/**
* Get List of Tags based on playbook and inventory file
*/
$scope.getTags = function(){
var inventory_file_name = $scope.selectedInventoryFile.value;
if(roleName){
inventory_file_name = roleName + '/tests/' + inventory_file_name;
}
var selectedPlaybookName = selectedPlaybook.playbook;
var ansibleEngine = angular.copy(selectedProject.ansibleEngine);
// Override project folder for roles
if(projectFolder)
ansibleEngine.projectFolder = projectFolder;
ansible.getTagList(selectedPlaybookName,inventory_file_name,ansibleEngine,
function(response){
console.log(response.data)
/*var re = /TAGS: \[(.*)\]/g;
var m;
var all_tags = []
while ((m = re.exec(response.data)) !== null) {
if (m.index === re.lastIndex) {
re.lastIndex++;
}
// View your result using the m-variable.
// eg m[0] etc.
if(m[1])
all_tags.push(m[1])
}
$scope.all_tags = all_tags.join(',').split(',');*/
if(!response.data.playbooks)return null;
var playbooks = response.data.playbooks;
$scope.all_hosts = [];
$scope.all_tags = [];
angular.forEach(playbooks, playbook => {
angular.forEach(playbook.plays, play => {
$scope.all_hosts = $scope.all_hosts.concat(play.hosts);
$scope.all_tags = $scope.all_tags.concat(play.tags);
angular.forEach(play.tasks, task => {
$scope.all_tags = $scope.all_tags.concat(task.tags);
})
})
});
// Get Unique List of tags
$scope.all_tags = Array.from(new Set($scope.all_tags));
// Get Unique List of hosts
$scope.all_hosts = Array.from(new Set($scope.all_hosts));
$scope.all_hosts = $scope.all_hosts.map(host => {return {name:host,selected:false}});
$scope.all_tags = $scope.all_tags.map(tag => {return {name:tag,selected:false}});
if(tags){
angular.forEach(tags, tag => {
var tag_found = false;
angular.forEach($scope.all_tags, (all_tag,index) => {
if(tag == all_tag.name){
tag_found = true;
all_tag.selected = true
}
});
if(!tag_found)
$scope.all_tags.push({name:tag,selected:true})
})
}
$scope.readyForPlay = true;
},
function(error){
//console.log(error.data)
//$scope.err_msg = error.data;
$scope.result = $sce.trustAsHtml(ansi2html.toHtml(error.data).replace(/\n/g, "<br>"));
$scope.view = 'console'
})
};
/**
* Process Ansible Output and show graphically
* @param ansibleOutput
*/
$scope.processAnsibleOutput_old = function(ansibleOutput){
$scope.ansibleOutputResult = [];
//https://regex101.com/r/yD6lZ6/1
//var re = /(PLAY|TASK) \[(.*)\] (.*)\n(.*?):([^]*?)(?=TASK|PLAY)/gm;
//var re = /(PLAY|TASK) \[(.*)\] (.*)\n(?:(.*?)\s?(.*): \[(.*)\](.*)=> ([^]*?)(?=TASK|PLAY)|(.*?): \[(.*)\](.*)|(.*)|(?=TASK|PLAY))/gm
//var re = /(PLAY|TASK) \[(.*)\] (.*)\n(?:(.*?)\s?(.*): \[(.*)\](.*)=> ([^]*?)(?=\n\n)|(.*?): \[(.*)\](.*)|(.*)|(?=\n\n))/gm;
var re = /({[^]+})/g
var m;
while ((m = re.exec(ansibleOutput)) !== null) {
if (m.index === re.lastIndex) {
re.lastIndex++;
}
// View your result using the m-variable.
// eg m[0] etc.
var type = m[1]; //TASK,PLAY
var name = m[2]; // ansible-role-vra : debug delete instance
var status = m[5]; //ok, skipping, failed
var host = m[6]; //localhost , localhost -> localhost
var status_2 = m[7];
var result = m[8];
if(result){
//var result_object_string = result.replace(/({[^]+})[^]+/,"$1");
var result_object_string = result;
var resultObject = null;
try{
resultObject = JSON.parse(result_object_string);
//resultObject.formattedStdErr = resultObject.stderr.replace(/\\r\\n/g,'<br>').replace(/\\n/g, "<br>");
resultObject.formattedStdErr = resultObject.stderr.replace(/\n/g,'<br>');
resultObject.formattedStdOut = resultObject.stderr.replace(/\n/g,'<br>');
}catch(e){
console.log("Error converting ansible output result object to javascript")
}
}
$scope.ansibleOutputResult.push({
type:type,
name:name,
status:status,
host:host,
status_2:status_2,
resultString:result,
resultObject:resultObject
})
}
}
$scope.processAnsibleOutput = function(ansibleOutput){
$scope.ansibleOutputResult = [];
$scope.ansibleOutputObject = {
'plays' : [],
'stats' : {}
}
//var re = /(.*{[^]+}.*)/g;
var re = /--------BEGIN--------([^]+?)--------END--------/gm;
var m;
while ((m = re.exec(ansibleOutput)) !== null) {
if (m.index === re.lastIndex) {
re.lastIndex++;
}
// View your result using the m-variable.
// eg m[0] etc.
try{
//$scope.ansibleOutputObject = JSON.parse(m[1]);
var resultItem = JSON.parse(m[1]);
if('play' in resultItem){
$scope.ansibleOutputObject.plays.push(resultItem);
} else if('task' in resultItem){
var current_play = $scope.ansibleOutputObject.plays[$scope.ansibleOutputObject.plays.length-1]
var newTask = true;
angular.forEach(current_play.tasks, (task, index)=>{
if(task.task.id === resultItem.task.id){
newTask = false;
current_play.tasks[index] = resultItem
}
})
if(newTask)
current_play.tasks.push(resultItem);
} else if('stats' in resultItem){
$scope.ansibleOutputObject.stats = resultItem.stats;
}
}catch(e){
console.log("Error parsing ansible output" + e);
}
//var plays = $scope.ansibleOutputObject.plays;
}
console.log($scope.ansibleOutputObject);
/*while ((m = re.exec(ansibleOutput)) !== null) {
if (m.index === re.lastIndex) {
re.lastIndex++;
}
// View your result using the m-variable.
// eg m[0] etc.
var type = m[1]; //TASK,PLAY
var name = m[2]; // ansible-role-vra : debug delete instance
var status = m[5]; //ok, skipping, failed
var host = m[6]; //localhost , localhost -> localhost
var status_2 = m[7];
var result = m[8];
if(result){
//var result_object_string = result.replace(/({[^]+})[^]+/,"$1");
var result_object_string = result;
var resultObject = null;
try{
resultObject = JSON.parse(result_object_string);
//resultObject.formattedStdErr = resultObject.stderr.replace(/\\r\\n/g,'<br>').replace(/\\n/g, "<br>");
resultObject.formattedStdErr = resultObject.stderr.replace(/\n/g,'<br>');
resultObject.formattedStdOut = resultObject.stderr.replace(/\n/g,'<br>');
}catch(e){
console.log("Error converting ansible output result object to javascript")
}
}
$scope.ansibleOutputResult.push({
type:type,
name:name,
status:status,
host:host,
status_2:status_2,
resultString:result,
resultObject:resultObject
})
}*/
}
}
export default angular.module('webAppApp.execution', [])
.controller('ExecutionController', executionController)
.name;

View file

@ -0,0 +1,17 @@
'use strict';
describe('Controller: ExecutionCtrl', function() {
// load the controller's module
beforeEach(module('webAppApp.execution'));
var ExecutionCtrl;
// Initialize the controller and a mock scope
beforeEach(inject(function($controller) {
ExecutionCtrl = $controller('ExecutionCtrl', {});
}));
it('should ...', function() {
expect(1).to.equal(1);
});
});