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