1# Used by the mmkubernetes tests
2# This is a simple http server which responds to kubernetes api requests
3# and responds with kubernetes api server responses
4# added 2018-04-06 by richm, released under ASL 2.0
5import os
6import json
7import sys
8
9try:
10    from http.server import HTTPServer, BaseHTTPRequestHandler
11except ImportError:
12    from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
13
14ns_template = '''{{
15  "kind": "Namespace",
16  "apiVersion": "v1",
17  "metadata": {{
18    "name": "{namespace_name}",
19    "selfLink": "/api/v1/namespaces/{namespace_name}",
20    "uid": "{namespace_name}-id",
21    "resourceVersion": "2988",
22    "creationTimestamp": "2018-04-09T21:56:39Z",
23    "labels": {{
24      "label.1.key":"label 1 value",
25      "label.2.key":"label 2 value",
26      "label.with.empty.value":""
27    }},
28    "annotations": {{
29      "k8s.io/description": "",
30      "k8s.io/display-name": "",
31      "k8s.io/node-selector": "",
32      "k8s.io/sa.scc.mcs": "s0:c9,c4",
33      "k8s.io/sa.scc.supplemental-groups": "1000080000/10000",
34      "k8s.io/sa.scc.uid-range": "1000080000/10000",
35      "quota.k8s.io/cluster-resource-override-enabled": "false"
36    }}
37  }},
38  "spec": {{
39    "finalizers": [
40      "openshift.io/origin",
41      "kubernetes"
42    ]
43  }},
44  "status": {{
45    "phase": "Active"
46  }}
47}}'''
48
49pod_template = '''{{
50  "kind": "Pod",
51  "apiVersion": "v1",
52  "metadata": {{
53    "name": "{pod_name}",
54    "generateName": "{pod_name}-prefix",
55    "namespace": "{namespace_name}",
56    "selfLink": "/api/v1/namespaces/{namespace_name}/pods/{pod_name}",
57    "uid": "{pod_name}-id",
58    "resourceVersion": "3486",
59    "creationTimestamp": "2018-04-09T21:56:39Z",
60    "labels": {{
61      "component": "{pod_name}-component",
62      "deployment": "{pod_name}-deployment",
63      "deploymentconfig": "{pod_name}-dc",
64      "custom.label": "{pod_name}-label-value",
65      "label.with.empty.value":""
66    }},
67    "annotations": {{
68      "k8s.io/deployment-config.latest-version": "1",
69      "k8s.io/deployment-config.name": "{pod_name}-dc",
70      "k8s.io/deployment.name": "{pod_name}-deployment",
71      "k8s.io/custom.name": "custom value",
72      "annotation.with.empty.value":""
73    }}
74  }},
75  "status": {{
76    "phase": "Running",
77    "hostIP": "172.18.4.32",
78    "podIP": "10.128.0.14",
79    "startTime": "2018-04-09T21:57:39Z"
80  }}
81}}'''
82
83err_template = '''{{
84  "kind": "Status",
85  "apiVersion": "v1",
86  "metadata": {{
87
88  }},
89  "status": "Failure",
90  "message": "{kind} \\\"{objectname}\\\" {err}",
91  "reason": "{reason}",
92  "details": {{
93    "name": "{objectname}",
94    "kind": "{kind}"
95  }},
96  "code": {code}
97}}'''
98
99is_busy = False
100
101class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
102
103    def do_GET(self):
104        # "http://localhost:18443/api/v1/namespaces/namespace-name2"
105        # parse url - either /api/v1/namespaces/$ns_name
106        # or
107        # /api/v1/namespaces/$ns_name/pods/$pod_name
108        global is_busy
109        comps = self.path.split('/')
110        status = 400
111        if len(comps) >= 5 and comps[1] == 'api' and comps[2] == 'v1' and comps[3] == 'namespaces':
112            resp = None
113            hsh = {'namespace_name':comps[4],'objectname':comps[4],'kind':'namespace'}
114            if len(comps) == 5: # namespace
115                resp_template = ns_template
116                status = 200
117            elif len(comps) == 7 and comps[5] == 'pods': # pod
118                hsh['pod_name'] = comps[6]
119                hsh['kind'] = 'pods'
120                hsh['objectname'] = hsh['pod_name']
121                resp_template = pod_template
122                status = 200
123            else:
124                resp = '{{"error":"do not recognize {0}"}}'.format(self.path)
125            if hsh['objectname'].endswith('not-found'):
126                status = 404
127                hsh['reason'] = 'NotFound'
128                hsh['err'] = 'not found'
129                resp_template = err_template
130            elif hsh['objectname'].endswith('busy'):
131                is_busy = not is_busy
132                if is_busy:
133                    status = 429
134                    hsh['reason'] = 'Busy'
135                    hsh['err'] = 'server is too busy'
136                    resp_template = err_template
137            elif hsh['objectname'].endswith('error'):
138                status = 500
139                hsh['reason'] = 'Error'
140                hsh['err'] = 'server is failing'
141                resp_template = err_template
142            if not resp:
143                hsh['code'] = status
144                resp = resp_template.format(**hsh)
145        else:
146            resp = '{{"error":"do not recognize {0}"}}'.format(self.path)
147        if not status == 200:
148            self.log_error(resp)
149        self.send_response(status)
150        self.end_headers()
151        self.wfile.write(json.dumps(json.loads(resp), separators=(',',':')).encode())
152
153port = int(sys.argv[1])
154
155httpd = HTTPServer(('localhost', port), SimpleHTTPRequestHandler)
156
157# write "started" to file named in argv[3]
158with open(sys.argv[3], "w") as ff:
159    ff.write("started\n")
160
161# write pid to file named in argv[2]
162with open(sys.argv[2], "w") as ff:
163    ff.write('{0}\n'.format(os.getpid()))
164
165httpd.serve_forever()
166