@@ -151,6 +151,10 @@ LabelSelector.prototype.hasConjunct = function(conjunct) {
151151 return this . _conjuncts [ this . _getIdForConjunct ( conjunct ) ] ? true : false ;
152152} ;
153153
154+ LabelSelector . prototype . findConjunctsMatching = function ( operator , key ) {
155+ return _ . pick ( this . _conjuncts , _ . matches ( { operator : operator , key : key } ) ) ;
156+ } ;
157+
154158// Test whether this label selector covers the given selector
155159LabelSelector . prototype . covers = function ( selector ) {
156160 if ( this . isEmpty ( ) ) {
@@ -159,15 +163,45 @@ LabelSelector.prototype.covers = function(selector) {
159163 return false ;
160164 }
161165
162- // TODO - currently k8s only returns key: value
163- // which represents 'key in (value)' So we only handle
164- // the IN operator with single values for now
165- for ( var id in this . _conjuncts ) {
166- if ( ! selector . hasConjunct ( this . _conjuncts [ id ] ) ) {
167- return false ;
166+ return _ . every ( this . _conjuncts , function ( conjunct ) {
167+ // Return true immediately if we find an exact match for operator/key/values
168+ if ( selector . hasConjunct ( conjunct ) ) {
169+ return true ;
168170 }
169- }
170- return true ;
171+
172+ // If we can't find a conjunct that matches exactly, do a more detailed check
173+ switch ( conjunct . operator ) {
174+ case "exists" :
175+ // If an Exists conjunct existed for the same key in selector it
176+ // would have passed the exact match, just need to check if an In
177+ // conjunct exists for the same key
178+ return ! _ . isEmpty ( selector . findConjunctsMatching ( "in" , conjunct . key ) ) ;
179+ case "does not exist" :
180+ // A DoesNotExist can only cover a DoesNotExist operator, if we got here
181+ // then we didn't have a DNE with the same key so we know we can't cover
182+ return false ;
183+ case "in" :
184+ // In (A,B,C) covers In (A,B) AND In (B,C)
185+ var inConjuncts = selector . findConjunctsMatching ( "in" , conjunct . key ) ;
186+ if ( _ . isEmpty ( inConjuncts ) ) {
187+ return false ;
188+ }
189+ return _ . every ( inConjuncts , function ( inConjunct ) {
190+ return inConjunct . values . length === _ . intersection ( inConjunct . values , conjunct . values ) . length ;
191+ } ) ;
192+ case "not in" :
193+ // NotIn (A,B) covers NotIn (A,B,C) AND NotIn (A,B,D)
194+ var notInConjuncts = selector . findConjunctsMatching ( "not in" , conjunct . key ) ;
195+ if ( _ . isEmpty ( notInConjuncts ) ) {
196+ return false ;
197+ }
198+ return _ . every ( notInConjuncts , function ( notInConjunct ) {
199+ return conjunct . values . length === _ . intersection ( notInConjunct . values , conjunct . values ) . length ;
200+ } ) ;
201+ }
202+
203+ return true ;
204+ } ) ;
171205} ;
172206
173207// Exports the labelSelector as a string in the API format, exports as matchExpressions
0 commit comments