Skip to content

Commit

Permalink
Merge pull request #4177 from fabianofranz/452_deployments_and_rollba…
Browse files Browse the repository at this point in the history
…cks_from_console

Merged by openshift-bot
  • Loading branch information
OpenShift Bot committed Sep 9, 2015
2 parents e61cc31 + 130dc47 commit c4c2695
Show file tree
Hide file tree
Showing 9 changed files with 961 additions and 263 deletions.
42 changes: 26 additions & 16 deletions assets/app/scripts/controllers/builds.js
Expand Up @@ -129,7 +129,31 @@ angular.module('openshiftConsole')
{
type: "error",
message: "An error occurred while starting the build.",
details: getErrorDetails(result)
details: $filter('getErrorDetails')(result)
}
];
}
);
};

$scope.cancelBuild = function(build, buildConfigName) {
var canceledBuild = angular.copy(build);
canceledBuild.status.cancelled = true;
DataService.update("builds", canceledBuild.metadata.name, canceledBuild, $scope).then(
function() {
$scope.alerts = [
{
type: "success",
message: "Cancelling build " + build.metadata.name + " of " + buildConfigName + ".",
}
];
},
function(result) {
$scope.alerts = [
{
type: "error",
message: "An error occurred cancelling the build.",
details: $filter('getErrorDetails')(result)
}
];
}
Expand Down Expand Up @@ -159,7 +183,7 @@ angular.module('openshiftConsole')
{
type: "error",
message: "An error occurred while rerunning the build.",
details: getErrorDetails(result)
details: $filter('getErrorDetails')(result)
}
];
}
Expand All @@ -175,20 +199,6 @@ angular.module('openshiftConsole')
});
});

function getErrorDetails(result) {
var error = result.data || {};
if (error.message) {
return error.message;
}

var status = result.status || error.status;
if (status) {
return "Status: " + status;
}

return "";
}

$scope.$on('$destroy', function(){
DataService.unwatchAll(watches);
});
Expand Down
238 changes: 237 additions & 1 deletion assets/app/scripts/controllers/deployments.js
Expand Up @@ -30,7 +30,7 @@ angular.module('openshiftConsole')
});
}

watches.push(DataService.watch("replicationcontrollers", $scope, function(deployments) {
watches.push(DataService.watch("replicationcontrollers", $scope, function(deployments, action, deployment) {
$scope.unfilteredDeployments = deployments.by("metadata.name");
LabelFilter.addLabelSuggestionsFromResources($scope.unfilteredDeployments, $scope.labelSuggestions);
LabelFilter.setLabelSuggestions($scope.labelSuggestions);
Expand All @@ -41,6 +41,27 @@ angular.module('openshiftConsole')
associateDeploymentsToDeploymentConfig();
updateFilterWarning();

var deploymentConfigName;
var deploymentName;
if (deployment) {
deploymentConfigName = $filter('annotation')(deployment, 'deploymentConfig');
deploymentName = deployment.metadata.name;
}
if (!action) {
// Loading of the page that will create deploymentConfigDeploymentsInProgress structure, which will associate running deployment to his deploymentConfig.
$scope.deploymentConfigDeploymentsInProgress = associateRunningDeploymentToDeploymentConfig($scope.deploymentsByDeploymentConfig);
} else if (action === 'ADDED' || (action === 'MODIFIED' && ['New', 'Pending', 'Running'].indexOf($scope.deploymentStatus(deployment)) > -1)) {
// When new deployment id instantiated/cloned, or in case of a retry, associate him to his deploymentConfig and add him into deploymentConfigDeploymentsInProgress structure.
$scope.deploymentConfigDeploymentsInProgress[deploymentConfigName] = $scope.deploymentConfigDeploymentsInProgress[deploymentConfigName] || {};
$scope.deploymentConfigDeploymentsInProgress[deploymentConfigName][deploymentName] = deployment;
} else if (action === 'MODIFIED') {
// After the deployment ends remove him from the deploymentConfigDeploymentsInProgress structure.
var deploymentStatus = $scope.deploymentStatus(deployment);
if (deploymentStatus === "Complete" || deploymentStatus === "Failed"){
delete $scope.deploymentConfigDeploymentsInProgress[deploymentConfigName][deploymentName];
}
}

Logger.log("deployments (subscribe)", $scope.deployments);
}));

Expand Down Expand Up @@ -73,6 +94,20 @@ angular.module('openshiftConsole')
});
}

function associateRunningDeploymentToDeploymentConfig(deploymentsByDeploymentConfig) {
var deploymentConfigDeploymentsInProgress = {};
angular.forEach(deploymentsByDeploymentConfig, function(deploymentConfigDeployments, deploymentConfigName) {
deploymentConfigDeploymentsInProgress[deploymentConfigName] = {};
angular.forEach(deploymentConfigDeployments, function(deployment, deploymentName) {
var deploymentStatus = $scope.deploymentStatus(deployment);
if (deploymentStatus === "New" || deploymentStatus === "Pending" || deploymentStatus === "Running") {
deploymentConfigDeploymentsInProgress[deploymentConfigName][deploymentName] = deployment;
}
});
});
return deploymentConfigDeploymentsInProgress;
}

function updateFilterWarning() {
if (!LabelFilter.getLabelSelector().isEmpty() && $.isEmptyObject($scope.deployments) && !$.isEmptyObject($scope.unfilteredDeployments)) {
$scope.alerts["deployments"] = {
Expand All @@ -85,6 +120,207 @@ angular.module('openshiftConsole')
}
}

$scope.startLatestDeployment = function(deploymentConfigName) {
var deploymentConfig = $scope.deploymentConfigs[deploymentConfigName];

// increase latest version by one so starts new deployment based on latest
var req = {
kind: "DeploymentConfig",
apiVersion: "v1",
metadata: deploymentConfig.metadata,
spec: deploymentConfig.spec,
status: deploymentConfig.status
};
if (!req.status.latestVersion) {
req.status.latestVersion = 0;
}
req.status.latestVersion++;

// update the deployment config
DataService.update("deploymentconfigs", deploymentConfigName, req, $scope).then(
function() {
$scope.alerts = [
{
type: "success",
message: "Deployment #" + req.status.latestVersion + " of " + deploymentConfigName + " has started.",
}
];
},
function(result) {
$scope.alerts = [
{
type: "error",
message: "An error occurred while starting the deployment.",
details: $filter('getErrorDetails')(result)
}
];
}
);
};

$scope.retryFailedDeployment = function(deploymentConfigName, deploymentName) {
var deployment = $scope.deploymentsByDeploymentConfig[deploymentConfigName][deploymentName];
var req = deployment;

// TODO: we need a "retry" api endpoint so we don't have to do this manually

// delete the deployer pod as well as the deployment hooks pods, if any
DataService.list("pods", $scope, function(list) {
var pods = list.by("metadata.name");
var deleteDeployerPod = function(pod) {
var deployerPodForAnnotation = $filter('annotationName')('deployerPodFor');
if (pod.metadata.labels[deployerPodForAnnotation] === deploymentName) {
DataService.delete("pods", pod.metadata.name, $scope).then(
function() {
Logger.info("Deployer pod " + pod.metadata.name + " deleted");
},
function(result) {
$scope.alerts = [
{
type: "error",
message: "An error occurred while deleting the deployer pod.",
details: $filter('getErrorDetails')(result)
}
];
}
);
}
};
angular.forEach(pods, deleteDeployerPod);
});

// set deployment to "New" and remove statuses so we can retry
var deploymentStatusAnnotation = $filter('annotationName')('deploymentStatus');
var deploymentStatusReasonAnnotation = $filter('annotationName')('deploymentStatusReason');
var deploymentCancelledAnnotation = $filter('annotationName')('deploymentCancelled');
req.metadata.annotations[deploymentStatusAnnotation] = "New";
delete req.metadata.annotations[deploymentStatusReasonAnnotation];
delete req.metadata.annotations[deploymentCancelledAnnotation];

// update the deployment
DataService.update("replicationcontrollers", deploymentName, req, $scope).then(
function() {
$scope.alerts = [
{
type: "success",
message: "Retrying deployment " + deploymentName + " of " + deploymentConfigName + ".",
}
];
},
function(result) {
$scope.alerts = [
{
type: "error",
message: "An error occurred while retrying the deployment.",
details: $filter('getErrorDetails')(result)
}
];
}
);
};

$scope.rollbackToDeployment = function(deploymentConfigName, deploymentName, changeScaleSettings, changeStrategy, changeTriggers) {
// put together a new rollback request
var req = {
kind: "DeploymentConfigRollback",
apiVersion: "v1",
spec: {
from: {
name: deploymentName
},
includeTemplate: true,
includeReplicationMeta: changeScaleSettings,
includeStrategy: changeStrategy,
includeTriggers: changeTriggers
}
};

// TODO: we need a "rollback" api endpoint so we don't have to do this manually

// create the deployment config rollback
DataService.create("deploymentconfigrollbacks", null, req, $scope).then(
function(newDeploymentConfig) {
// update the deployment config based on the one returned by the rollback
DataService.update("deploymentconfigs", deploymentConfigName, newDeploymentConfig, $scope).then(
function(rolledBackDeploymentConfig) {
$scope.alerts = [
{
type: "success",
message: "Deployment #" + rolledBackDeploymentConfig.status.latestVersion + " is rolling back " + deploymentConfigName + " to " + deploymentName + ".",
}
];
},
function(result) {
$scope.alerts = [
{
type: "error",
message: "An error occurred while rolling back the deployment.",
details: $filter('getErrorDetails')(result)
}
];
}
);
},
function(result) {
$scope.alerts = [
{
type: "error",
message: "An error occurred while rolling back the deployment.",
details: $filter('getErrorDetails')(result)
}
];
}
);
};

$scope.cancelRunningDeployment = function(deploymentConfigName, deploymentName) {
var deployment = $scope.deploymentsByDeploymentConfig[deploymentConfigName][deploymentName];
var req = deployment;

// TODO: we need a "cancel" api endpoint so we don't have to do this manually

// set the cancellation annotations
var deploymentCancelledAnnotation = $filter('annotationName')('deploymentCancelled');
var deploymentStatusReasonAnnotation = $filter('annotationName')('deploymentStatusReason');
req.metadata.annotations[deploymentCancelledAnnotation] = "true";
req.metadata.annotations[deploymentStatusReasonAnnotation] = "The deployment was cancelled by the user";

// update the deployment with cancellation annotations
DataService.update("replicationcontrollers", deploymentName, req, $scope).then(
function() {
$scope.alerts = [
{
type: "success",
message: "Cancelling deployment " + deploymentName + " of " + deploymentConfigName + ".",
}
];
},
function(result) {
$scope.alerts = [
{
type: "error",
message: "An error occurred while cancelling the deployment.",
details: $filter('getErrorDetails')(result)
}
];
}
);
};

$scope.deploymentIsLatest = function(deploymentConfig, deployment) {
var deploymentVersion = parseInt($filter('annotation')(deployment, 'deploymentVersion'));
var deploymentConfigVersion = deploymentConfig.status.latestVersion;
return deploymentVersion === deploymentConfigVersion;
};

$scope.deploymentStatus = function(deployment) {
return $filter('annotation')(deployment, 'deploymentStatus');
};

$scope.deploymentIsInProgress = function(deployment) {
return ['New', 'Pending', 'Running'].indexOf($scope.deploymentStatus(deployment)) > -1;
};

LabelFilter.onActiveFiltersChanged(function(labelSelector) {
// trigger a digest loop
$scope.$apply(function() {
Expand Down
38 changes: 23 additions & 15 deletions assets/app/scripts/filters/resources.js
Expand Up @@ -14,28 +14,36 @@ angular.module('openshiftConsole')
}
};
})
.filter('annotation', function() {
// This maps an annotation key to all known synonymous keys to insulate
// the referring code from key renames across API versions.
var annotationMap = {
"deploymentConfig": ["openshift.io/deployment-config.name"],
"deployment": ["openshift.io/deployment.name"],
"pod": ["openshift.io/deployer-pod.name"],
"deploymentStatus": ["openshift.io/deployment.phase"],
"encodedDeploymentConfig": ["openshift.io/encoded-deployment-config"],
"deploymentVersion": ["openshift.io/deployment-config.latest-version"],
"displayName": ["openshift.io/display-name"],
"description": ["openshift.io/description"],
"buildNumber": ["openshift.io/build.number"]
};
.filter('annotationName', function() {
return function(annotationKey) {
// This maps an annotation key to all known synonymous keys to insulate
// the referring code from key renames across API versions.
var annotationMap = {
"deploymentConfig": ["openshift.io/deployment-config.name"],
"deployment": ["openshift.io/deployment.name"],
"pod": ["openshift.io/deployer-pod.name"],
"deployerPodFor": ["openshift.io/deployer-pod-for.name"],
"deploymentStatus": ["openshift.io/deployment.phase"],
"deploymentStatusReason": ["openshift.io/deployment.status-reason"],
"deploymentCancelled": ["openshift.io/deployment.cancelled"],
"encodedDeploymentConfig": ["openshift.io/encoded-deployment-config"],
"deploymentVersion": ["openshift.io/deployment-config.latest-version"],
"displayName": ["openshift.io/display-name"],
"description": ["openshift.io/description"],
"buildNumber": ["openshift.io/build.number"]
};
return annotationMap[annotationKey] || null;
};
})
.filter('annotation', function(annotationNameFilter) {
return function(resource, key) {
if (resource && resource.metadata && resource.metadata.annotations) {
// If the key's already in the annotation map, return it.
if (resource.metadata.annotations[key] !== undefined) {
return resource.metadata.annotations[key];
}
// Try and return a value for a mapped key.
var mappings = annotationMap[key] || [];
var mappings = annotationNameFilter(key) || [];
for (var i=0; i < mappings.length; i++) {
var mappedKey = mappings[i];
if (resource.metadata.annotations[mappedKey] !== undefined) {
Expand Down

0 comments on commit c4c2695

Please sign in to comment.