Skip to content

add more detail to specific service types #839

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 78 additions & 2 deletions app/scripts/controllers/service.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ angular.module('openshiftConsole')
$filter) {
$scope.projectName = $routeParams.project;
$scope.service = null;
$scope.services = null;
$scope.alerts = {};
$scope.renderOptions = $scope.renderOptions || {};
$scope.renderOptions.hideFilterWidget = true;
Expand All @@ -27,11 +28,60 @@ angular.module('openshiftConsole')
}
];

$scope.podFailureReasons = {
"Pending": "This pod will not receive traffic until all of its containers have been created."
};

var allPods = {};
var watches = [];

// receives routes for the current service and maps service ports to each route name
var getPortsByRoute = function() {
if(!$scope.service) {
return;
}

$scope.portsByRoute = {};

_.each($scope.service.spec.ports, function(port) {
var reachedByRoute = false;
if(port.nodePort) {
$scope.showNodePorts = true;
}

_.each($scope.routesForService, function(route) {
if(!route.spec.port || route.spec.port.targetPort === port.name ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@spadgett you are more familiar with the route / port stuff, can you review this section

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks correct.

route.spec.port.targetPort === port.targetPort) {
$scope.portsByRoute[route.metadata.name] = $scope.portsByRoute[route.metadata.name] || [];
$scope.portsByRoute[route.metadata.name].push(port);
reachedByRoute = true;
}
});

if(!reachedByRoute) {
$scope.portsByRoute[''] = $scope.portsByRoute[''] || [];
$scope.portsByRoute[''].push(port);
}
});
};

// receive pods for the current service scope only when the service object is available
var getPodsForService = function() {
$scope.podsForService = {};
if (!$scope.service) {
return;
}

var ls = new LabelSelector($scope.service.spec.selector);
$scope.podsForService = ls.select(allPods);
};
var serviceResolved = function(service, action) {
$scope.loaded = true;
$scope.service = service;

getPodsForService();
getPortsByRoute();

if (action === "DELETED") {
$scope.alerts["deleted"] = {
type: "warning",
Expand Down Expand Up @@ -60,15 +110,41 @@ angular.module('openshiftConsole')
}
);

watches.push(DataService.watch("services", context, function(services) {
$scope.services = services.by("metadata.name");
}));

watches.push(DataService.watch("pods", context, function(pods) {
allPods = pods.by("metadata.name");
getPodsForService();
}));

watches.push(DataService.watch("endpoints", context, function(endpoints) {
$scope.podsWithEndpoints = {};
var svcEndpoint = endpoints.by("metadata.name")[$routeParams.service];
if (!svcEndpoint) {
return;
}

_.each(svcEndpoint.subsets, function(subset) {
_.each(subset.addresses, function(address) {
if (_.get(address, "targetRef.kind") === "Pod") {
$scope.podsWithEndpoints[address.targetRef.name] = true;
}
});
});
}));

watches.push(DataService.watch("routes", context, function(routes) {
$scope.routesForService = [];
$scope.routesForService = {};
angular.forEach(routes.by("metadata.name"), function(route) {
if (route.spec.to.kind === "Service" &&
route.spec.to.name === $routeParams.service) {
$scope.routesForService.push(route);
$scope.routesForService[route.metadata.name] = route;
}
});

getPortsByRoute();
Logger.log("routes (subscribe)", $scope.routesByService);
}));

Expand Down
24 changes: 23 additions & 1 deletion app/scripts/directives/resources.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,31 @@ angular.module('openshiftConsole')
restrict: 'E',
scope: {
pods: '=',
// Optional active pods map to display whether or not pods have endpoints
activePods: '=?',
// Optional empty message to display when there are no pods.
emptyMessage: '=?'
emptyMessage: '=?',
// Alternative header text to display in the 'Name' column.
customNameHeader: '=?',
// Optional map of explanations or warnings for each phase of a pod
podFailureReasons: '=?'
},
templateUrl: 'views/directives/pods-table.html'
};
})
.directive('trafficTable', function() {
return {
restrict: 'E',
scope: {
routes: '=',
services: '=',
portsByRoute: '=',
showNodePorts: '=?',
// Optional empty message to display when there are no pods.
emptyMessage: '=?',
// Alternative header text to display in the 'Name' column.
customNameHeader: '=?',
},
templateUrl: 'views/directives/traffic-table.html'
};
});
8 changes: 4 additions & 4 deletions app/views/browse/routes.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,23 @@ <h1>
<div class="container-fluid">
<alerts alerts="alerts"></alerts>
<div class="row">
<div class="col-md-12">
<div class="col-md-12 gutter-top">
<table class="table table-bordered table-hover table-mobile">
<thead>
<tr>
<th>Name</th>
<th>{{customNameHeader || 'Name'}}</th>
<th>Hostname</th>
<th>Routes To</th>
<th>Target Port</th>
<th>TLS Termination</th>
</tr>
</thead>
<tbody ng-if="(routes | hashSize) == 0">
<tr><td colspan="5"><em>{{emptyMessage}}</em></td></tr>
<tr><td colspan="5"><em>{{emptyMessage || 'No routes to show'}}</em></td></tr>
</tbody>
<tbody ng-repeat="route in routes | orderObjectsByDate : true">
<tr>
<td data-title="Name">
<td data-title="{{ customNameHeader || 'Name' }}">
<a href="{{route | navigateResourceURL}}">{{route.metadata.name}}</a>
<route-warnings ng-if="route.spec.to.kind !== 'Service' || services"
route="route"
Expand Down
69 changes: 33 additions & 36 deletions app/views/browse/service.html
Original file line number Diff line number Diff line change
Expand Up @@ -62,50 +62,47 @@ <h1>
<dd>{{service.spec.type}}</dd>
<dt>IP:</dt>
<dd>{{service.spec.clusterIP}}</dd>
<dt>Hostname:</dt>
<dd>
{{service.metadata.name}}.{{service.metadata.namespace}}.svc
<span data-toggle="popover" data-trigger="hover" data-content="{{'This address is only resolvable from within the cluster.'}}" style="cursor: help; padding-left: 5px;">
<span class="pficon pficon-info" aria-hidden="true" data-toggle="tooltip" style="cursor: help;"></span>
</span>
</dd>
<dt ng-if-start="service.spec.externalName">External Hostname:</dt>
<dd ng-if-end>{{service.spec.externalName}}</dd>
<dt>Session affinity:</dt>
<dd>{{service.spec.sessionAffinity}}</dd>
<dt ng-if="resource.status.loadBalancer.ingress.length">Ingress points</dt>
<dd ng-if="resource.status.loadBalancer.ingress.length">
<span ng-repeat="ingress in resource.status.loadBalancer.ingress"
<dt ng-if-start="service.status.loadBalancer.ingress.length">Ingress Points:</dt>
<dd ng-if-end>
<span ng-repeat="ingress in service.status.loadBalancer.ingress"
>{{ingress.ip}}<span ng-if="!$last">, </span></span>
</dd>
<dt>Routes:</dt>
<dd>
<span ng-if="!routesForService.length">
<dt ng-if-start="service.spec.externalIPs.length">External IPs:</dt>
<dd ng-if-end>
<span ng-repeat="externalIP in service.spec.externalIPs"
>{{externalIP}}<span ng-if="!$last">, </span></span>
</dd>
<dt ng-if-start="(routesForService | hashSize) == 0">Routes:</dt>
<dd ng-if-end>
<span>
<a ng-href="project/{{project.metadata.name}}/create-route?service={{service.metadata.name}}" ng-if="'routes' | canI : 'create'">Create route</a>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if user doesn't have access to create routes, this should say <em>none</em>

</span>
<span ng-repeat="route in routesForService">
<span ng-if="route | isWebRoute"><a ng-href="{{route | routeWebURL}}">{{route | routeLabel}}</a></span>
<span ng-if="!(route | isWebRoute)">{{route | routeLabel}}</span>
<span ng-show="!$last">, </span>
<span ng-if="!('routes' | canI : 'create')"><em>None</em></span>
</span>
</dd>
</dl>
<div ng-if="service.spec.ports.length" class="table-responsive">
<table class="table table-bordered small service-table">
<thead>
<tr>
<th>Node Port</th>
<th role="presentation"></th>
<th>Service Port</th>
<th role="presentation"></th>
<th>Target Port</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="portMapping in service.spec.ports | orderBy:'port'">
<td>
<span ng-if="portMapping.nodePort">{{portMapping.nodePort}}</span>
<span ng-if="!portMapping.nodePort" class="text-muted">none</span>
</td>
<td role="presentation" class="text-muted">&#8594;</td>
<td>{{portMapping.port}}/{{portMapping.protocol}}
<span ng-if="portMapping.name">({{portMapping.name}})</span></td>
<td role="presentation" class="text-muted">&#8594;</td>
<td>{{portMapping.targetPort}}</td>
</tr>
</tbody>
</table>
<h3>
Traffic
</h3>
<div class="table-responsive">
<traffic-table ports-by-route="portsByRoute" routes="routesForService" services="services" show-node-ports="showNodePorts" custom-name-header="'Route'"></traffic-table>
</div>
<div style="margin:-10px 0 10px 0;">
Learn more about <a ng-href="{{'route-types' | helpLink}}" target="_blank">routes</a> and <a ng-href="{{'services' | helpLink}}" target="_blank">services</a>
</div>
<h3>Pods</h3>
<div class="table-responsive">
<pods-table pods="podsForService" active-pods="podsWithEndpoints" custom-name-header="'Pod'" pod-failure-reasons="podFailureReasons"></pods-table>
</div>
<annotations annotations="service.metadata.annotations"></annotations>
</div>
Expand Down
19 changes: 16 additions & 3 deletions app/views/directives/pods-table.html
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
<table class="table table-bordered table-hover table-mobile">
<thead>
<tr>
<th>Name</th>
<th>{{customNameHeader || 'Name'}}</th>
<th>Status</th>
<th>Containers Ready</th>
<th>Container Restarts</th>
<th>Age</th>
<th ng-if="activePods">Receiving Traffic</th>
</tr>
</thead>
<tbody ng-if="(pods | hashSize) == 0">
<tr><td colspan="5"><em>{{emptyMessage || 'No pods to show'}}</em></td></tr>
<tr><td colspan="6"><em>{{emptyMessage || 'No pods to show'}}</em></td></tr>
</tbody>
<tbody ng-repeat="pod in pods | orderObjectsByDate : true">
<tr>
<td data-title="Name">
<td data-title="{{customNameHeader || 'Name'}}">
<a href="{{pod | navigateResourceURL}}">{{pod.metadata.name}}</a>
<span ng-if="pod | isDebugPod">
<i class="fa fa-bug info-popover"
Expand All @@ -33,6 +34,18 @@
<td data-title="Ready">{{pod | numContainersReady}}/{{pod.spec.containers.length}}</td>
<td data-title="Restarts">{{pod | numContainerRestarts}}</td>
<td data-title="Age"><span am-time-ago="pod.metadata.creationTimestamp" am-without-suffix="true"></span></td>
<td ng-if="activePods" data-title="Receiving Traffic">
<span ng-if="activePods[pod.metadata.name]">
<span class="fa fa-fw fa-check text-success" aria-hidden="true"></span>
<span class="sr-only">Yes</span>
</span>
<span ng-if="!activePods[pod.metadata.name]">
<span data-toggle="popover" data-trigger="hover" data-content="{{podFailureReasons[pod.status.phase] || 'This pod has no endpoints and is not accepting traffic.'}}" style="cursor: help;">
<span class="fa fa-fw fa-times text-danger" aria-hidden="true" data-toggle="tooltip" style="cursor: help;"></span>
<span class="sr-only">No</span>
</span>
</span>
</td>
</tr>
</tbody>
</table>
78 changes: 78 additions & 0 deletions app/views/directives/traffic-table.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<!-- Table combining routes and ports for a service -->
<table class="table table-bordered table-hover table-mobile">
<thead>
<tr>
<th>{{customNameHeader || 'Route'}}<span ng-if="showNodePorts"> / Node Port</span></th>
<th role="presentation"></th>
<th>Service Port</th>
<th role="presentation"></th>
<th>Target Port</th>
<th>Hostname</th>
<th>TLS Termination</th>
</tr>
</thead>
<tbody ng-if="(portsByRoute | hashSize) == 0">
<tr><td colspan="7"><em>{{emptyMessage || 'No routes or ports to show'}}</em></td></tr>
</tbody>
<tbody ng-if="(portsByRoute | hashSize) > 0">
<tr ng-repeat-start="(routeName,ports) in portsByRoute" style="display:none;"></tr>
<tr ng-repeat="port in ports" ng-if="routeName !== ''">
<td data-title="{{customNameHeader || 'Route'}}{{ showNodePorts ? ' / Node Port' : '' }}">
<a href="{{routes[routeName] | navigateResourceURL}}">{{routes[routeName].metadata.name}}</a>
<route-warnings ng-if="routes[routeName].spec.to.kind !== 'Service' || services"
route="routes[routeName]"
service="services[routes[routeName].spec.to.name]">
</route-warnings>
<span ng-if="showNodePorts">
<span ng-if="port.nodePort"> / {{port.nodePort}}</span>
</span>
</td>
<td role="presentation" class="text-muted">&#8594;</td>
<td data-title="Service Port">
{{port.port}}/{{port.protocol}}
<span ng-if="port.name">({{port.name}})</span>
</td>
<td role="presentation" class="text-muted">&#8594;</td>
<td data-title="Target Port">
{{port.targetPort}}
</td>
<td data-title="Hostname">
<span ng-if="(routes[routeName] | isWebRoute)" class="word-break">
<a href="{{routes[routeName] | routeWebURL}}" target="_blank">{{routes[routeName] | routeLabel}}</a>
</span>
<span ng-if="!(routes[routeName] | isWebRoute)" class="word-break">
{{routes[routeName] | routeLabel}}
</span>
<span ng-if="!routes[routeName].status.ingress" data-toggle="popover" data-trigger="hover" data-content="The route is not accepting traffic yet because it has not been admitted by a router." style="cursor: help; padding-left: 5px;">
<status-icon status="'Pending'" disable-animation></status-icon>
<span class="sr-only">Pending</span>
</span>
</td>
<!-- Use shorter Termination title for table-mobile to avoid overlapping text. -->
<td data-title="Termination">
{{routes[routeName].spec.tls.termination}}
<span ng-if="!routes[routeName].spec.tls.termination">&nbsp;</span>
</td>
</tr>
<tr ng-repeat-end style="display:none;"></tr>
<tr ng-repeat="port in portsByRoute['']">
<td data-title="{{customNameHeader || 'Route'}}{{ showNodePorts ? ' / Node Port' : '' }}">
<span ng-if="!port.nodePort" class="text-muted">none</span>
<span ng-if="port.nodePort">{{port.nodePort}}</span>
</td>
<td role="presentation" class="text-muted">&#8594;</td>
<td data-title="Service Port">
{{port.port}}/{{port.protocol}}
<span ng-if="port.name">({{port.name}})</span>
</td>
<td role="presentation" class="text-muted">&#8594;</td>
<td data-title="Target Port">
{{port.targetPort}}
</td>
<td data-title="Hostname"><span class="text-muted">none</span></td>
<td data-title="Termination">
<span class="text-muted">none</span>
</td>
</tr>
</tbody>
</table>
Loading