@@ -42,12 +42,18 @@ def parse_backend(self, backend, is_default=False):
4242 Parses ingress backend and returns the set of pods and ports referenced by it.
4343 :param dict backend: the backend resource
4444 :param bool is_default: whether this is the default backend
45- :return: a tuple PeerSet and PortSet: the sets of pods and ports referenced by the backend,
46- or None and all ports when the default backend is None,
47- or None and None when the non-default backend is None.
45+ :return: a tuple PeerSet and PortSet and a bool flag, as following:
46+ the sets of pods and ports referenced by the backend and True,
47+ or None and all ports and True when the default backend is None ,
48+ or None and None and True when the non-default backend is None,
49+ or None and None and False when the backend is not None but backend service does not exist (for default and
50+ non-default backends)
51+ - for non-default backend when the flag is False then the backend service does not exist, and the path
52+ containing this backend should be ignored (i.e. don't override its peers and ports from the default_backend)
53+ :rtype: (PeerSet, PortSet, bool)
4854 """
4955 if backend is None :
50- return (None , PortSet (True )) if is_default else (None , None )
56+ return (None , PortSet (True ), True ) if is_default else (None , None , True )
5157 allowed_elements = {'resource' : [0 , dict ], 'service' : [0 , dict ]}
5258 self .check_fields_validity (backend , 'backend' , allowed_elements )
5359 resource = backend .get ('resource' )
@@ -57,7 +63,7 @@ def parse_backend(self, backend, is_default=False):
5763 f'in the ingress { "default" if is_default else "" } backend' , backend )
5864 if resource :
5965 self .warning ('Resource is not yet supported in an ingress backend. Ignoring' , backend )
60- return (None , PortSet (True )) if is_default else (None , None )
66+ return (None , PortSet (True ), True ) if is_default else (None , None , True )
6167 allowed_service_elements = {'name' : [1 , str ], 'port' : [1 , dict ]}
6268 self .check_fields_validity (service , 'backend service' , allowed_service_elements )
6369 service_name = service .get ('name' )
@@ -73,31 +79,41 @@ def parse_backend(self, backend, is_default=False):
7379 self .validate_value_in_domain (port_number , 'dst_ports' , backend , 'Port number' )
7480 srv = self .peer_container .get_service_by_name_and_ns (service_name , self .namespace )
7581 if not srv :
76- self .syntax_error (f'Missing service referenced by the ingress { "default" if is_default else "" } backend' ,
77- service )
82+ warning_msg = f'The service referenced by the ingress { "default" if is_default else "" } ' \
83+ f'backend does not exist. '
84+ if is_default :
85+ warning_msg += 'The default backend will be ignored'
86+ else :
87+ warning_msg += 'The rule path containing this backend service will be ignored'
88+ self .warning (warning_msg , service )
89+ return None , None , False
90+
7891 service_port = srv .get_port_by_name (port_name ) if port_name else srv .get_port_by_number (port_number )
7992 if not service_port :
8093 self .syntax_error (f'Missing port { port_name if port_name else port_number } in the service' , service )
8194
8295 rule_ports = PortSet ()
8396 rule_ports .add_port (service_port .target_port ) # may be either a number or a named port
84- return srv .target_pods , rule_ports
97+ return srv .target_pods , rule_ports , True
8598
8699 def parse_ingress_path (self , path ):
87100 """
88101 Parses ingress path resource.
89102 The assumption is that the default backend has been already parsed
90103 :param dict path: the path resource
91- :return: a tuple (path_string, path_type, peers, ports)
104+ :return: a tuple (path_string, path_type, peers, ports) or None if the path to be ignored
92105 """
93106 self .check_fields_validity (path , 'ingress rule path' ,
94107 {'backend' : [1 , dict ], 'path' : [0 , str ], 'pathType' : [1 , str ]},
95108 {'pathType' : ['ImplementationSpecific' , 'Exact' , 'Prefix' ]})
96109
97110 backend = path .get ('backend' )
98- peers , ports = self .parse_backend (backend )
111+ peers , ports , override_default = self .parse_backend (backend )
99112 if not peers :
100- peers , ports = self .default_backend_peers , self .default_backend_ports
113+ if override_default :
114+ peers , ports = self .default_backend_peers , self .default_backend_ports
115+ else : # backend service does not exist , ignoring this path
116+ return None
101117 path_string = path .get ('path' )
102118 path_type = path .get ('pathType' )
103119 # from https://docs.nginx.com/nginx-ingress-controller/configuration/ingress-resources/basic-configuration/
@@ -193,26 +209,30 @@ def parse_rule(self, rule):
193209 hosts_dfa = self .parse_regex_host_value (rule .get ("host" ), rule )
194210 paths_array = self .get_key_array_and_validate_not_empty (rule .get ('http' ), 'paths' )
195211 allowed_conns = None
212+ default_conns = None
196213 if paths_array is not None :
197214 all_paths_dfa = None
198215 parsed_paths = []
199216 for path in paths_array :
200- parsed_paths .append (self .parse_ingress_path (path ))
201- parsed_paths_with_dfa = self .segregate_longest_paths_and_make_dfa (parsed_paths )
202- for (_ , paths_dfa , _ , peers , ports ) in parsed_paths_with_dfa :
203- # every path is converted to allowed connections
204- conns = self ._make_tcp_like_properties (ports , peers , paths_dfa , hosts_dfa )
205- if not allowed_conns :
206- allowed_conns = conns
207- else :
208- allowed_conns |= conns
209- if not all_paths_dfa :
210- all_paths_dfa = paths_dfa
211- else :
212- all_paths_dfa = all_paths_dfa | paths_dfa # pick all captured paths
213- # for this host, every path not captured by the above paths goes to the default backend or is denied
214- paths_remainder_dfa = DimensionsManager ().get_dimension_domain_by_name ('paths' ) - all_paths_dfa
215- default_conns = self ._make_default_connections (hosts_dfa , paths_remainder_dfa )
217+ path_resources = self .parse_ingress_path (path )
218+ if path_resources is not None :
219+ parsed_paths .append (path_resources )
220+ if parsed_paths :
221+ parsed_paths_with_dfa = self .segregate_longest_paths_and_make_dfa (parsed_paths )
222+ for (_ , paths_dfa , _ , peers , ports ) in parsed_paths_with_dfa :
223+ # every path is converted to allowed connections
224+ conns = self ._make_tcp_like_properties (ports , peers , paths_dfa , hosts_dfa )
225+ if not allowed_conns :
226+ allowed_conns = conns
227+ else :
228+ allowed_conns |= conns
229+ if not all_paths_dfa :
230+ all_paths_dfa = paths_dfa
231+ else :
232+ all_paths_dfa = all_paths_dfa | paths_dfa # pick all captured paths
233+ # for this host, every path not captured by the above paths goes to the default backend or is denied
234+ paths_remainder_dfa = DimensionsManager ().get_dimension_domain_by_name ('paths' ) - all_paths_dfa
235+ default_conns = self ._make_default_connections (hosts_dfa , paths_remainder_dfa )
216236 else : # no paths --> everything for this host goes to the default backend or is denied
217237 default_conns = self ._make_default_connections (hosts_dfa )
218238 if allowed_conns and default_conns :
@@ -240,8 +260,8 @@ def parse_policy(self):
240260 'rules' : [0 , list ], 'tls' : [0 , list ]}
241261 self .check_fields_validity (policy_spec , 'Ingress spec' , allowed_spec_keys )
242262
243- self .default_backend_peers , self .default_backend_ports = self .parse_backend (policy_spec .get ('defaultBackend' ),
244- True )
263+ self .default_backend_peers , self .default_backend_ports , _ = self .parse_backend (policy_spec .get ('defaultBackend' ),
264+ True )
245265 # TODO extend to other ingress controllers
246266 res_policy .selected_peers = \
247267 self .peer_container .get_pods_with_service_name_containing_given_string ('ingress-nginx' )
@@ -251,10 +271,11 @@ def parse_policy(self):
251271 all_hosts_dfa = None
252272 for ingress_rule in policy_spec .get ('rules' , []):
253273 conns , hosts_dfa = self .parse_rule (ingress_rule )
254- if not allowed_conns :
255- allowed_conns = conns
256- else :
257- allowed_conns |= conns
274+ if conns :
275+ if not allowed_conns :
276+ allowed_conns = conns
277+ else :
278+ allowed_conns |= conns
258279 if hosts_dfa :
259280 if not all_hosts_dfa :
260281 all_hosts_dfa = hosts_dfa
@@ -269,8 +290,10 @@ def parse_policy(self):
269290 allowed_conns |= default_conns
270291 elif default_conns :
271292 allowed_conns = default_conns
272- assert allowed_conns
273293
274- res_policy .add_rules (self ._make_allow_rules (allowed_conns ))
294+ # allowed_conns = none means that services referenced by this Ingress policy are not found,
295+ # then no connections rules to add (Ingress policy has no effect)
296+ if allowed_conns :
297+ res_policy .add_rules (self ._make_allow_rules (allowed_conns ))
275298 res_policy .findings = self .warning_msgs
276299 return res_policy
0 commit comments