|
| 1 | +'use strict'; |
| 2 | +/* jshint unused: false */ |
| 3 | + |
| 4 | +/** |
| 5 | + * @ngdoc function |
| 6 | + * @name openshiftConsole.controller:MonitoringController |
| 7 | + * @description |
| 8 | + * # MonitoringController |
| 9 | + * Controller of the openshiftConsole |
| 10 | + */ |
| 11 | +angular.module('openshiftConsole') |
| 12 | + .controller('MonitoringController', function ($routeParams, |
| 13 | + $scope, |
| 14 | + $filter, |
| 15 | + DataService, |
| 16 | + ProjectsService, |
| 17 | + MetricsService, |
| 18 | + BuildsService, |
| 19 | + PodsService, |
| 20 | + Logger, |
| 21 | + ImageStreamResolver, |
| 22 | + $rootScope) { |
| 23 | + $scope.projectName = $routeParams.project; |
| 24 | + $scope.alerts = $scope.alerts || {}; |
| 25 | + $scope.renderOptions = $scope.renderOptions || {}; |
| 26 | + $scope.renderOptions.showEventsSidebar = true; |
| 27 | + |
| 28 | + var watches = []; |
| 29 | + |
| 30 | + $scope.kindSelector = { |
| 31 | + selected: { |
| 32 | + kind: "All" |
| 33 | + } |
| 34 | + }; |
| 35 | + $scope.kinds = [ |
| 36 | + { |
| 37 | + kind: "Pods" |
| 38 | + }, |
| 39 | + { |
| 40 | + kind: "Builds" |
| 41 | + }, |
| 42 | + { |
| 43 | + label: "Deployments", |
| 44 | + kind: "ReplicationControllers" |
| 45 | + }, |
| 46 | + { |
| 47 | + kind: "All" |
| 48 | + } |
| 49 | + ]; |
| 50 | + |
| 51 | + $scope.logOptions = { |
| 52 | + pods: {}, |
| 53 | + deployments: {}, |
| 54 | + builds: {} |
| 55 | + }; |
| 56 | + |
| 57 | + $scope.logCanRun = { |
| 58 | + pods: {}, |
| 59 | + deployments: {}, |
| 60 | + builds: {} |
| 61 | + }; |
| 62 | + |
| 63 | + $scope.logEmpty = { |
| 64 | + pods: {}, |
| 65 | + deployments: {}, |
| 66 | + builds: {} |
| 67 | + }; |
| 68 | + |
| 69 | + $scope.filters = { |
| 70 | + showOlderResources: false, |
| 71 | + text: '' |
| 72 | + }; |
| 73 | + |
| 74 | + var ageFilteredBuilds, ageFilteredDeployments, ageFilteredPods; |
| 75 | + |
| 76 | + // Check if the metrics service is available so we know when to show the tab. |
| 77 | + MetricsService.isAvailable().then(function(available) { |
| 78 | + $scope.metricsAvailable = available; |
| 79 | + }); |
| 80 | + |
| 81 | + var orderByDate = $filter('orderObjectsByDate'); |
| 82 | + |
| 83 | + var filterExpressions = []; |
| 84 | + var updateKeywords = function() { |
| 85 | + if (!$scope.filters.text) { |
| 86 | + filterExpressions = []; |
| 87 | + return; |
| 88 | + } |
| 89 | + |
| 90 | + var keywords = _.uniq($scope.filters.text.split(/\s+/)); |
| 91 | + // Sort the longest keyword first. |
| 92 | + keywords.sort(function(a, b){ |
| 93 | + return b.length - a.length; |
| 94 | + }); |
| 95 | + |
| 96 | + // Convert the keyword to a case-insensitive regular expression for the filter. |
| 97 | + filterExpressions = _.map(keywords, function(keyword) { |
| 98 | + return new RegExp(_.escapeRegExp(keyword), "i"); |
| 99 | + }); |
| 100 | + }; |
| 101 | + |
| 102 | + // Only filter by keyword on certain fields. |
| 103 | + var filterFields = [ |
| 104 | + 'metadata.name' |
| 105 | + ]; |
| 106 | + |
| 107 | + var filterForKeyword = function(resources) { |
| 108 | + var filteredResources = resources; |
| 109 | + if (!filterExpressions.length) { |
| 110 | + return filteredResources; |
| 111 | + } |
| 112 | + |
| 113 | + // Find events that match all keywords. |
| 114 | + angular.forEach(filterExpressions, function(regex) { |
| 115 | + var matchesKeyword = function(event) { |
| 116 | + var i; |
| 117 | + for (i = 0; i < filterFields.length; i++) { |
| 118 | + var value = _.get(event, filterFields[i]); |
| 119 | + if (value && regex.test(value)) { |
| 120 | + return true; |
| 121 | + } |
| 122 | + } |
| 123 | + |
| 124 | + return false; |
| 125 | + }; |
| 126 | + |
| 127 | + filteredResources = _.filter(filteredResources, matchesKeyword); |
| 128 | + }); |
| 129 | + return filteredResources; |
| 130 | + }; |
| 131 | + |
| 132 | + var filterAllResourcesForKeyword = function() { |
| 133 | + $scope.filteredPods = filterForKeyword(ageFilteredPods); |
| 134 | + $scope.filteredDeployments = filterForKeyword(ageFilteredDeployments); |
| 135 | + $scope.filteredBuilds = filterForKeyword(ageFilteredBuilds); |
| 136 | + }; |
| 137 | + |
| 138 | + var setPodLogVars = function(pod) { |
| 139 | + $scope.logOptions.pods[pod.metadata.name] = { |
| 140 | + container: pod.spec.containers[0].name |
| 141 | + }; |
| 142 | + $scope.logCanRun.pods[pod.metadata.name] = !(_.includes(['New', 'Pending', 'Unknown'], pod.status.phase)); |
| 143 | + }; |
| 144 | + |
| 145 | + var setDeploymentLogVars = function(deployment) { |
| 146 | + $scope.logOptions.deployments[deployment.metadata.name] = { |
| 147 | + container: $filter("annotation")(deployment, "pod") |
| 148 | + }; |
| 149 | + var deploymentVersion = $filter("annotation")(deployment, "deploymentVersion"); |
| 150 | + if (deploymentVersion) { |
| 151 | + $scope.logOptions.deployments[deployment.metadata.name].version = deploymentVersion; |
| 152 | + } |
| 153 | + $scope.logCanRun.deployments[deployment.metadata.name] = !(_.includes(['New', 'Pending'], $filter('deploymentStatus')(deployment))); |
| 154 | + }; |
| 155 | + |
| 156 | + var setBuildLogVars = function(build) { |
| 157 | + $scope.logOptions.builds[build.metadata.name] = { |
| 158 | + container: $filter("annotation")(build, "buildPod") |
| 159 | + }; |
| 160 | + $scope.logCanRun.builds[build.metadata.name] = !(_.includes(['New', 'Pending', 'Error'], build.status.phase)); |
| 161 | + }; |
| 162 | + |
| 163 | + var filterPods = function() { |
| 164 | + ageFilteredPods = _.filter($scope.pods, function(pod) { |
| 165 | + if ($scope.filters.showOlderResources) { |
| 166 | + return true; |
| 167 | + } |
| 168 | + if (pod.status.phase !== 'Succeeded' && pod.status.phase !== 'Failed') { |
| 169 | + return true; |
| 170 | + } |
| 171 | + return false; |
| 172 | + }); |
| 173 | + }; |
| 174 | + |
| 175 | + var isIncompleteBuild = $filter('isIncompleteBuild'); |
| 176 | + var buildConfigForBuild = $filter('buildConfigForBuild'); |
| 177 | + var filterBuilds = function() { |
| 178 | + var fiveMinutesAgo = moment().subtract(5, 'm'); |
| 179 | + ageFilteredBuilds = _.filter($scope.builds, function(build) { |
| 180 | + if ($scope.filters.showOlderResources) { |
| 181 | + return true; |
| 182 | + } |
| 183 | + if (isIncompleteBuild(build)) { |
| 184 | + return true; |
| 185 | + } |
| 186 | + var buildConfigName = buildConfigForBuild(build); |
| 187 | + if (buildConfigName) { |
| 188 | + return $scope.latestBuildByConfig[buildConfigName].metadata.name === build.metadata.name; |
| 189 | + } |
| 190 | + |
| 191 | + // Otherwise this is a one-off build, keep any of those that finished in the last 5 minutes, if we |
| 192 | + // don't have a completionTimestamp for some reason then fallback to creationTimestamp |
| 193 | + var completed = moment(build.status.completionTimestamp || build.metadata.creationTimestamp); |
| 194 | + return completed.isAfter(fiveMinutesAgo); |
| 195 | + }); |
| 196 | + }; |
| 197 | + |
| 198 | + var deploymentStatus = $filter('deploymentStatus'); |
| 199 | + var filterDeployments = function() { |
| 200 | + ageFilteredDeployments = _.filter($scope.deployments, function(deployment) { |
| 201 | + if ($scope.filters.showOlderResources) { |
| 202 | + return true; |
| 203 | + } |
| 204 | + var status = deploymentStatus(deployment); |
| 205 | + if (status !== 'Complete' && status !== 'Failed') { |
| 206 | + return true; |
| 207 | + } |
| 208 | + return false; |
| 209 | + }); |
| 210 | + }; |
| 211 | + |
| 212 | + $scope.toggleItem = function(resource, expanded) { |
| 213 | + var event = expanded ? 'event.resource.highlight' : 'event.resource.clear-highlight'; |
| 214 | + $rootScope.$emit(event, resource); |
| 215 | + if (resource.kind === 'Build') { |
| 216 | + var buildPod = _.get($scope.podsByName, $filter('annotation')(resource, 'buildPod')); |
| 217 | + if (buildPod) { |
| 218 | + $rootScope.$emit(event, buildPod); |
| 219 | + } |
| 220 | + } |
| 221 | + if (resource.kind === 'ReplicationController') { |
| 222 | + var deployerPodName = $filter('annotation')(resource, 'deployerPod'); |
| 223 | + if (deployerPodName) { |
| 224 | + // The deployer pod is deleted immediately so mock the resource to send to the event highlighter |
| 225 | + $rootScope.$emit(event, { |
| 226 | + kind: "Pod", |
| 227 | + metadata: { |
| 228 | + name: deployerPodName |
| 229 | + } |
| 230 | + }); |
| 231 | + } |
| 232 | + _.each($scope.podsByDeployment[resource.metadata.name], function(pod) { |
| 233 | + $rootScope.$emit(event, pod); |
| 234 | + }); |
| 235 | + } |
| 236 | + }; |
| 237 | + |
| 238 | + var groupPods = function() { |
| 239 | + if (!$scope.pods || !$scope.deployments) { |
| 240 | + return; |
| 241 | + } |
| 242 | + |
| 243 | + $scope.podsByDeployment = PodsService.groupByReplicationController($scope.pods, $scope.deployments); |
| 244 | + }; |
| 245 | + |
| 246 | + ProjectsService |
| 247 | + .get($routeParams.project) |
| 248 | + .then(_.spread(function(project, context) { |
| 249 | + $scope.project = project; |
| 250 | + $scope.projectContext = context; |
| 251 | + |
| 252 | + DataService.watch("pods", context, function(pods) { |
| 253 | + $scope.podsByName = pods.by("metadata.name"); |
| 254 | + $scope.pods = orderByDate($scope.podsByName, true); |
| 255 | + groupPods(); |
| 256 | + _.each($scope.pods, function(pod) { |
| 257 | + setPodLogVars(pod); |
| 258 | + }); |
| 259 | + filterPods(); |
| 260 | + Logger.log("pods", $scope.pods); |
| 261 | + }); |
| 262 | + |
| 263 | + DataService.watch("replicationcontrollers", context, function(deployments) { |
| 264 | + $scope.deployments = orderByDate(deployments.by("metadata.name"), true); |
| 265 | + groupPods(); |
| 266 | + _.each($scope.deployments, function(deployment) { |
| 267 | + setDeploymentLogVars(deployment); |
| 268 | + }); |
| 269 | + filterDeployments(); |
| 270 | + Logger.log("deployments", $scope.deployments); |
| 271 | + }); |
| 272 | + |
| 273 | + DataService.watch("builds", context, function(builds) { |
| 274 | + $scope.builds = orderByDate(builds.by("metadata.name"), true); |
| 275 | + $scope.latestBuildByConfig = BuildsService.latestBuildByConfig($scope.builds); |
| 276 | + _.each($scope.builds, function(build) { |
| 277 | + setBuildLogVars(build); |
| 278 | + }); |
| 279 | + filterBuilds(); |
| 280 | + Logger.log("builds", $scope.builds); |
| 281 | + }); |
| 282 | + |
| 283 | + $scope.$on('$destroy', function(){ |
| 284 | + DataService.unwatchAll(watches); |
| 285 | + }); |
| 286 | + |
| 287 | + $scope.$watchGroup(['filters.showOlderResources'], function() { |
| 288 | + filterPods(); |
| 289 | + filterBuilds(); |
| 290 | + filterDeployments(); |
| 291 | + filterAllResourcesForKeyword(); |
| 292 | + }); |
| 293 | + |
| 294 | + $scope.$watch('filters.text', _.debounce(function() { |
| 295 | + updateKeywords(); |
| 296 | + $scope.$apply(filterAllResourcesForKeyword); |
| 297 | + }, 50, { maxWait: 250 })); |
| 298 | + |
| 299 | + })); |
| 300 | + }); |
0 commit comments