11from scheduler .exceptions import KubeHTTPException
22from scheduler .resources import Resource
33
4- MANIFEAT_CLASSES = {}
54
5+ class BaseIngress (Resource ):
6+ abstract = True
7+ api_version = 'networking.k8s.io/v1'
8+ api_prefix = 'apis'
9+ short_name = 'ingress'
10+ ingress_path = "/"
11+ ingress_class = None
612
7- class BaseManifest (object ):
8-
9- def manifest (self , api_version , ingress , ingress_class , namespace , ** kwargs ):
10- path = "/*" if ingress_class in ("gce" , "alb" ) else "/"
13+ def manifest (self , ingress , ** kwargs ):
1114 hosts , tls = kwargs .pop ("hosts" , None ), kwargs .pop ("tls" , None )
1215 version = kwargs .pop ("version" , None )
1316 data = {
1417 "kind" : "Ingress" ,
15- "apiVersion" : api_version ,
18+ "apiVersion" : self . api_version ,
1619 "metadata" : {
1720 "name" : ingress ,
1821 "annotations" : {
1922 "kubernetes.io/tls-acme" : "true" ,
23+ "kubernetes.io/ingress.class" : self .ingress_class
2024 }
2125 },
2226 "spec" : {}
@@ -27,7 +31,7 @@ def manifest(self, api_version, ingress, ingress_class, namespace, **kwargs):
2731 "http" : {
2832 "paths" : [
2933 {
30- "path" : path ,
34+ "path" : self . ingress_path ,
3135 "pathType" : "Prefix" ,
3236 "backend" : {
3337 "service" : {
@@ -41,72 +45,12 @@ def manifest(self, api_version, ingress, ingress_class, namespace, **kwargs):
4145 ]
4246 }
4347 } for host in hosts ]
44- if ingress_class :
45- data ["metadata" ]["annotations" ].update ({
46- "kubernetes.io/ingress.class" : ingress_class
47- })
4848 if tls :
4949 data ["spec" ]["tls" ] = tls
5050 if version :
5151 data ["metadata" ]["resourceVersion" ] = version
5252 return data
5353
54-
55- class NginxManifest (BaseManifest ):
56-
57- def manifest (self , api_version , ingress , ingress_class , namespace , ** kwargs ):
58- data = BaseManifest .manifest (
59- self , api_version , ingress , ingress_class , namespace , ** kwargs )
60- if "allowlist" in kwargs :
61- allowlist = ", " .join (kwargs .pop ("allowlist" ))
62- data ["metadata" ]["annotations" ].update ({
63- "nginx.ingress.kubernetes.io/whitelist-source-range" : allowlist
64- })
65- if "ssl_redirect" in kwargs :
66- ssl_redirect = kwargs .pop ("ssl_redirect" )
67- data ["metadata" ]["annotations" ].update ({
68- "nginx.ingress.kubernetes.io/ssl-redirect" : ssl_redirect
69- })
70- return data
71-
72-
73- MANIFEAT_CLASSES ["nginx" ] = NginxManifest
74-
75-
76- class TraefikManifest (BaseManifest ):
77-
78- def manifest (self , api_version , ingress , ingress_class , namespace , ** kwargs ):
79- data = BaseManifest .manifest (
80- self , api_version , ingress , ingress_class , namespace , ** kwargs )
81- if "allowlist" in kwargs :
82- allowlist = ", " .join (kwargs .pop ("allowlist" ))
83- data ["metadata" ]["annotations" ].update ({
84- "ingress.kubernetes.io/whitelist-x-forwarded-for" : "true" ,
85- "traefik.ingress.kubernetes.io/whitelist-source-range" : allowlist
86- })
87- if "ssl_redirect" in kwargs :
88- ssl_redirect = kwargs .pop ("ssl_redirect" )
89- data ["metadata" ]["annotations" ].update ({
90- "ingress.kubernetes.io/ssl-redirect" : ssl_redirect
91- })
92- return data
93-
94-
95- MANIFEAT_CLASSES ["traefik" ] = TraefikManifest
96-
97-
98- class Ingress (Resource ):
99-
100- api_version = 'networking.k8s.io/v1'
101- api_prefix = 'apis'
102- short_name = 'ingress'
103-
104- @staticmethod
105- def manifest (api_version , ingress , ingress_class , namespace , ** kwargs ):
106- return MANIFEAT_CLASSES .get (ingress_class , BaseManifest )().manifest (
107- api_version , ingress , ingress_class , namespace , ** kwargs
108- )
109-
11054 def get (self , namespace , ingress = None , ** kwargs ):
11155 """
11256 Fetch a single Ingress or a list of Ingresses
@@ -124,28 +68,28 @@ def get(self, namespace, ingress=None, **kwargs):
12468
12569 return response
12670
127- def create (self , ingress , ingress_class , namespace , ** kwargs ):
71+ def create (self , namespace , ingress , ** kwargs ):
12872 url = self .api ("/namespaces/{}/ingresses" , namespace )
129- data = self .manifest (self . api_version , ingress , ingress_class , namespace , ** kwargs )
73+ data = self .manifest (ingress , ** kwargs )
13074 response = self .http_post (url , json = data )
13175
132- if not response .status_code == 201 :
76+ if self . unhealthy ( response .status_code ) :
13377 raise KubeHTTPException (response , "create Ingress {}" .format (namespace ))
13478
13579 return response
13680
137- def put (self , ingress , ingress_class , namespace , version , ** kwargs ):
81+ def put (self , namespace , ingress , version , ** kwargs ):
13882 url = self .api ("/namespaces/{}/ingresses/{}" , namespace , ingress )
13983 kwargs ["version" ] = version
140- data = self .manifest (self . api_version , ingress , ingress_class , namespace , ** kwargs )
84+ data = self .manifest (ingress , ** kwargs )
14185 response = self .http_put (url , json = data )
14286
14387 if self .unhealthy (response .status_code ):
14488 raise KubeHTTPException (response , "put Ingress {}" .format (namespace ))
14589
14690 return response
14791
148- def patch (self , ingress , namespace , data ):
92+ def patch (self , namespace , ingress , data , ** kwargs ):
14993 url = self .api ("/namespaces/{}/ingresses/{}" , namespace , ingress )
15094 response = self .http_put (url , json = data )
15195
@@ -161,3 +105,157 @@ def delete(self, namespace, ingress):
161105 raise KubeHTTPException (response , 'delete Ingress "{}"' , namespace )
162106
163107 return response
108+
109+
110+ class IngressFactory (Resource ):
111+
112+ short_name = 'ingress'
113+ ingress_class_map = {
114+ "default" : BaseIngress
115+ }
116+
117+ def __call__ (self , ingress_name ):
118+ ingress_cls = self .ingress_class_map .get (ingress_name , self .ingress_class_map ["default" ])
119+ ingress_cls .ingress_class = ingress_name
120+ return ingress_cls (self .url , self .k8s_api_verify_tls )
121+
122+ @classmethod
123+ def register (cls , ingress_name , ingress_cls ):
124+ cls .ingress_class_map [ingress_name ] = ingress_cls
125+
126+
127+ class NginxIngress (BaseIngress ):
128+
129+ def manifest (self , ingress , ** kwargs ):
130+ data = BaseIngress .manifest (self , ingress , ** kwargs )
131+ if "allowlist" in kwargs :
132+ allowlist = ", " .join (kwargs .pop ("allowlist" ))
133+ data ["metadata" ]["annotations" ].update ({
134+ "nginx.ingress.kubernetes.io/whitelist-source-range" : allowlist
135+ })
136+ if "ssl_redirect" in kwargs :
137+ ssl_redirect = kwargs .pop ("ssl_redirect" )
138+ data ["metadata" ]["annotations" ].update ({
139+ "nginx.ingress.kubernetes.io/ssl-redirect" : ssl_redirect
140+ })
141+ return data
142+
143+
144+ class TraefikIngress (BaseIngress ):
145+
146+ class Middleware (Resource ):
147+ abstract = True
148+ api_version = 'traefik.containo.us/v1alpha1'
149+ api_prefix = 'apis'
150+
151+ def manifest (self , name , allowlist , ssl_redirect , resource_version = None ):
152+ manifest = {
153+ "apiVersion" : self .api_version ,
154+ "kind" : "Middleware" ,
155+ "metadata" : {
156+ "name" : name
157+ },
158+ "spec" : {}
159+ }
160+ if allowlist :
161+ manifest ["spec" ]["ipWhiteList" ] = {
162+ "sourceRange" : allowlist
163+ }
164+ if ssl_redirect :
165+ manifest ["spec" ]["redirectScheme" ] = {
166+ "scheme" : "https" ,
167+ "permanent" : True
168+ }
169+ if resource_version :
170+ manifest ["metadata" ]["resourceVersion" ] = resource_version
171+ return manifest
172+
173+ def get (self , namespace , name = None , ** kwargs ):
174+ """
175+ Fetch a single Middleware or a list of Middlewares
176+ """
177+ if name is not None :
178+ url = self .api ("/namespaces/{}/middlewares/{}" , namespace , name )
179+ else :
180+ url = self .api ("/namespaces/{}/middlewares" , namespace )
181+ return self .http_get (url , params = self .query_params (** kwargs ))
182+
183+ def create (self , namespace , name , allowlist , ssl_redirect ):
184+ url = self .api ("/namespaces/{}/middlewares" , namespace )
185+ data = self .manifest (name , allowlist , ssl_redirect )
186+ response = self .http_put (url , json = data )
187+ if self .unhealthy (response .status_code ):
188+ raise KubeHTTPException (response , "create middleware {}" .format (namespace ))
189+ return response
190+
191+ def put (self , namespace , name , allowlist , ssl_redirect , resource_version ):
192+ url = self .api ("/namespaces/{}/middlewares/{}" , namespace , name )
193+ data = self .manifest (allowlist , ssl_redirect , resource_version )
194+ response = self .http_put (url , json = data )
195+ if self .unhealthy (response .status_code ):
196+ raise KubeHTTPException (response , "put middleware {}" .format (namespace ))
197+ return response
198+
199+ def create_or_put (self , namespace , name , allowlist , ssl_redirect ):
200+ response = self .get (namespace , name )
201+ if response .status_code == 404 :
202+ return self .create (namespace , name , allowlist , ssl_redirect )
203+ elif self .unhealthy (response .status_code ):
204+ raise KubeHTTPException (response , "get middleware {}" .format (namespace ))
205+ resource_version = response .json ()["metadata" ]["resourceVersion" ]
206+ return self .put (namespace , name , allowlist , ssl_redirect , resource_version )
207+
208+ def delete (self , namespace , name ):
209+ url = self .api ("/namespaces/{}/middlewares/{}" , namespace , name )
210+ response = self .http_delete (url )
211+ if self .unhealthy (response .status_code ):
212+ raise KubeHTTPException (response , 'delete middlewares "{}"' , namespace )
213+
214+ return response
215+
216+ def __init__ (self , url , k8s_api_verify_tls = True ):
217+ super ().__init__ (url , k8s_api_verify_tls )
218+ self .middleware = self .Middleware (url , k8s_api_verify_tls )
219+
220+ def create (self , namespace , ingress , ** kwargs ):
221+ response = super ().create (ingress , namespace , ** kwargs )
222+ if "allowlist" in kwargs or "ssl_redirect" in kwargs :
223+ self .middleware .create_or_put (
224+ namespace , ingress ,
225+ kwargs .get ("allowlist" ), kwargs .get ("ssl_redirect" )
226+ )
227+ return response
228+
229+ def put (self , namespace , ingress , version , ** kwargs ):
230+ response = super ().put (ingress , namespace , version , ** kwargs )
231+ if "allowlist" in kwargs or "ssl_redirect" in kwargs :
232+ self .middleware .create_or_put (
233+ namespace , ingress ,
234+ kwargs .get ("allowlist" ), kwargs .get ("ssl_redirect" )
235+ )
236+ return response
237+
238+ def patch (self , namespace , ingress , data , ** kwargs ):
239+ response = super ().patch (ingress , namespace , data , ** kwargs )
240+ if "allowlist" in kwargs or "ssl_redirect" in kwargs :
241+ self .middleware .create_or_put (
242+ namespace , ingress ,
243+ kwargs .get ("allowlist" ), kwargs .get ("ssl_redirect" )
244+ )
245+ return response
246+
247+ def delete (self , namespace , ingress ):
248+ response = super ().delete (namespace , ingress )
249+ if not self .unhealthy (self .middleware .get (namespace , ingress )):
250+ self .middleware .delete (namespace , ingress )
251+ return response
252+
253+
254+ class WildcardPathIngress (BaseIngress ):
255+ ingress_path = "/*"
256+
257+
258+ IngressFactory .register ("nginx" , NginxIngress )
259+ IngressFactory .register ("traefik" , TraefikIngress )
260+ IngressFactory .register ("gce" , WildcardPathIngress )
261+ IngressFactory .register ("alb" , WildcardPathIngress )
0 commit comments