From 65875b4492a1dd620d2ea1a0b73da73c83c1b3d5 Mon Sep 17 00:00:00 2001 From: Denis Poisson Date: Wed, 8 Jun 2016 13:04:09 +0200 Subject: [PATCH] Status icons for Services visible on list and resources pages + no labels handled (#845) --- .../backend/resource/service/servicecommon.go | 1 + .../backend/resource/service/servicelist.go | 4 ++ src/app/externs/backendapi.js | 1 + .../common/components/labels/labels.html | 19 ++--- .../frontend/servicelist/servicecardlist.html | 13 +++- .../servicelist/servicecardlist_component.js | 33 +++++++++ src/app/frontend/servicelist/servicelist.html | 2 +- ...eplicationcontrollercard_component_test.js | 1 + .../servicecardlist_component_test.js | 69 +++++++++++++++++++ 9 files changed, 133 insertions(+), 10 deletions(-) diff --git a/src/app/backend/resource/service/servicecommon.go b/src/app/backend/resource/service/servicecommon.go index c0d6d30bf..8db9881fa 100644 --- a/src/app/backend/resource/service/servicecommon.go +++ b/src/app/backend/resource/service/servicecommon.go @@ -29,6 +29,7 @@ func ToService(service *api.Service) Service { // TODO(maciaszczykm): Fill ExternalEndpoints with data. Selector: service.Spec.Selector, ClusterIP: service.Spec.ClusterIP, + Type: service.Spec.Type, } } diff --git a/src/app/backend/resource/service/servicelist.go b/src/app/backend/resource/service/servicelist.go index 3bd768985..6f782894b 100644 --- a/src/app/backend/resource/service/servicelist.go +++ b/src/app/backend/resource/service/servicelist.go @@ -17,6 +17,7 @@ package service import ( "log" + "k8s.io/kubernetes/pkg/api" client "k8s.io/kubernetes/pkg/client/unversioned" "github.com/kubernetes/dashboard/resource/common" @@ -38,6 +39,9 @@ type Service struct { // Label selector of the service. Selector map[string]string `json:"selector"` + // Type determines how the service will be exposed. Valid options: ClusterIP, NodePort, LoadBalancer + Type api.ServiceType `json:"type"` + // ClusterIP is usually assigned by the master. Valid values are None, empty string (""), or // a valid IP address. None can be specified for headless services when proxying is not required ClusterIP string `json:"clusterIP"` diff --git a/src/app/externs/backendapi.js b/src/app/externs/backendapi.js index 737e2d0f8..3b6733f84 100644 --- a/src/app/externs/backendapi.js +++ b/src/app/externs/backendapi.js @@ -407,6 +407,7 @@ backendApi.ServiceDetail; * internalEndpoint: !backendApi.Endpoint, * externalEndpoints: !Array, * selector: !Object, + * type: string, * clusterIP: string * }} */ diff --git a/src/app/frontend/common/components/labels/labels.html b/src/app/frontend/common/components/labels/labels.html index 37aa02d4c..a72f08eff 100644 --- a/src/app/frontend/common/components/labels/labels.html +++ b/src/app/frontend/common/components/labels/labels.html @@ -14,12 +14,15 @@ See the License for the specific language governing permissions and limitations under the License. --> - - -
- {{labelsCtrl.isShowingAll() ? - labelsCtrl.i18n.MSG_LABELS_SHOW_LESS_TOOLTIP : labelsCtrl.i18n.MSG_LABELS_SHOW_ALL_TOOLTIP}} +
+ + +
+ {{labelsCtrl.isShowingAll() ? + labelsCtrl.i18n.MSG_LABELS_SHOW_LESS_TOOLTIP : labelsCtrl.i18n.MSG_LABELS_SHOW_ALL_TOOLTIP}} +
+
-
diff --git a/src/app/frontend/servicelist/servicecardlist.html b/src/app/frontend/servicelist/servicecardlist.html index 635f35052..c1761ea0f 100644 --- a/src/app/frontend/servicelist/servicecardlist.html +++ b/src/app/frontend/servicelist/servicecardlist.html @@ -27,6 +27,15 @@ limitations under the License. + + + timelapse + {{::$ctrl.i18n.MSG_POD_IS_PENDING_TOOLTIP}} + + + check_circle + + @@ -36,7 +45,9 @@ limitations under the License. - {{::service.clusterIP}} + +
{{::$ctrl.getServiceClusterIP(service)}}
+
diff --git a/src/app/frontend/servicelist/servicecardlist_component.js b/src/app/frontend/servicelist/servicecardlist_component.js index 2216d8495..893555d7b 100644 --- a/src/app/frontend/servicelist/servicecardlist_component.js +++ b/src/app/frontend/servicelist/servicecardlist_component.js @@ -40,6 +40,37 @@ export class ServiceCardListController { return this.state_.href( stateName, new StateParams(service.objectMeta.namespace, service.objectMeta.name)); } + + /** + * Returns true if Service has no assigned Cluster IP + * or if Service type is LoadBalancer or NodePort and doesn't have an external endpoint IP + * @param {!backendApi.Service} service + * @return {boolean} + * @export + */ + isPending(service) { + return service.clusterIP === null || + ((service.type === 'LoadBalancer' || service.type === 'NodePort') && + service.externalEndpoints === null); + } + + /** + * Returns true if Service has ClusterIP assigned and one of the following conditions is met: + * - Service type is LoadBalancer or NodePort and has an external endpoint IP + * - Service type is not LoadBalancer or NodePort + * @param {!backendApi.Service} service + * @return {boolean} + * @export + */ + isSuccess(service) { return !this.isPending(service); } + + /** + * Returns the service's clusterIP or a dash ('-') if it is not yet set + * @param {!backendApi.Service} service + * @return {string} + * @export + */ + getServiceClusterIP(service) { return service.clusterIP ? service.clusterIP : '-'; } } /** @@ -76,4 +107,6 @@ const i18n = { /** @export {string} @desc Label 'External endpoints' which appears as a column label in the table of services (service list view). */ MSG_SERVICE_LIST_EXTERNAL_ENDPOINTS_LABEL: goog.getMsg('External endpoints'), + /** @export {string} @desc tooltip for pending pod card icon */ + MSG_SERVICE_IS_PENDING_TOOLTIP: goog.getMsg('This service is in a pending state.'), }; diff --git a/src/app/frontend/servicelist/servicelist.html b/src/app/frontend/servicelist/servicelist.html index 70caf9f8e..0b12cb8c4 100644 --- a/src/app/frontend/servicelist/servicelist.html +++ b/src/app/frontend/servicelist/servicelist.html @@ -16,6 +16,6 @@ limitations under the License. - + diff --git a/src/test/frontend/replicationcontrollerlist/replicationcontrollercard_component_test.js b/src/test/frontend/replicationcontrollerlist/replicationcontrollercard_component_test.js index 9abc42ca2..9c792e8c9 100644 --- a/src/test/frontend/replicationcontrollerlist/replicationcontrollercard_component_test.js +++ b/src/test/frontend/replicationcontrollerlist/replicationcontrollercard_component_test.js @@ -11,6 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. + import replicationControllerListModule from 'replicationcontrollerlist/replicationcontrollerlist_module'; describe('Replication controller card', () => { diff --git a/src/test/frontend/servicelist/servicecardlist_component_test.js b/src/test/frontend/servicelist/servicecardlist_component_test.js index 2f8216cfb..f6f4cf316 100644 --- a/src/test/frontend/servicelist/servicecardlist_component_test.js +++ b/src/test/frontend/servicelist/servicecardlist_component_test.js @@ -38,4 +38,73 @@ describe('Service list controller', () => { }, })).toBe('#/service/foo-namespace/foo-service'); }); + + it('should return true when service.clusterIP is null', () => { + expect(ctrl.isPending({ + clusterIP: null, + })).toBeTruthy(); + }); + + it('should return false when service.clusterIP is set', () => { + expect(ctrl.isPending({ + clusterIP: '10.67.252.103', + })).toBeFalsy(); + }); + + it('should return true when service.type is LoadBalancer AND service.externalEndpoints is null', + () => { + expect(ctrl.isPending({ + clusterIP: '10.67.252.103', + type: 'LoadBalancer', + externalEndpoints: null, + })).toBeTruthy(); + }); + + it('should return true when service.type is NodePort AND service.externalEndpoints is null', + () => { + expect(ctrl.isPending({ + clusterIP: '10.67.252.103', + type: 'NodePort', + externalEndpoints: null, + })).toBeTruthy(); + }); + + it('should return true when service.type is LoadBalancer AND service.externalEndpoints is set', + () => { + expect(ctrl.isSuccess({ + clusterIP: '10.67.252.103', + type: 'LoadBalancer', + externalEndpoints: ['10.64.0.4:80', '10.64.1.5:80', '10.64.2.4:80'], + })).toBeTruthy(); + }); + + it('should return true when service.type is NodePort AND service.externalEndpoints is set', + () => { + expect(ctrl.isSuccess({ + clusterIP: '10.67.252.103', + type: 'NodePort', + externalEndpoints: ['10.64.0.4:80', '10.64.1.5:80', '10.64.2.4:80'], + })).toBeTruthy(); + }); + + it('should return true when service.type is ClusterIP and service.externalEndpoints is null', + () => { + expect(ctrl.isSuccess({ + clusterIP: '10.67.252.103', + type: 'ClusterIP', + externalEndpoints: null, + })).toBeTruthy(); + }); + + it('should return the service clusterIP when teh clusterIP is set', () => { + expect(ctrl.getServiceClusterIP({ + clusterIP: '10.67.252.103', + })).toBe('10.67.252.103'); + }); + + it('should return the service clusterIP when teh clusterIP is set', () => { + expect(ctrl.getServiceClusterIP({ + clusterIP: null, + })).toBe('-'); + }); }); -- GitLab