|
8 | 8 |
|
9 | 9 | class AppURLFinder(CRBase): |
10 | 10 |
|
11 | | - def get_ingresses(self, resources): |
12 | | - ingress_list = [] |
13 | | - for resource in resources: |
14 | | - #print(resource) |
15 | | - if resource['Kind'] == 'Ingress': |
16 | | - present = False |
17 | | - for s in ingress_list: |
18 | | - if s['Name'] == resource['Name']: |
19 | | - present = True |
20 | | - break |
21 | | - if not present: |
22 | | - ingress_list.append(resource) |
23 | | - #print(ingress_list) |
24 | | - return ingress_list |
| 11 | + def _get_node_ips(self, kubeconfig): |
| 12 | + node_ip_types = [] |
| 13 | + node_ips = [] |
| 14 | + node_list = [] |
25 | 15 |
|
26 | | - def get_svc(self, resources): |
27 | | - svc_list = [] |
28 | | - for resource in resources: |
29 | | - #print(resource) |
30 | | - if resource['Kind'] == 'Service': |
31 | | - present = False |
32 | | - for s in svc_list: |
33 | | - if s['Name'] == resource['Name']: |
34 | | - present = True |
35 | | - break |
36 | | - if not present: |
37 | | - svc_list.append(resource) |
38 | | - #print(svc_list) |
39 | | - return svc_list |
| 16 | + # get all the nodes |
| 17 | + get_nodes = "kubectl get nodes " + kubeconfig |
| 18 | + out, err = self.run_command(get_nodes) |
| 19 | + for line in out.split("\n"): |
| 20 | + line1 = ' '.join(line.split()) |
| 21 | + if 'NAME' not in line1 and line1 != '': |
| 22 | + parts = line1.split(" ") |
| 23 | + nodename = parts[0].strip() |
| 24 | + node_list.append(nodename) |
40 | 25 |
|
41 | | - def get_host_from_ingress(self, ingresses, namespace, kubeconfig): |
42 | | - appURL = "" |
43 | | - for ingress in ingresses: |
44 | | - cmd = 'kubectl get ingress ' + ingress['Name'] + ' -n ' + ingress['Namespace'] + ' -o json ' + kubeconfig |
45 | | - #print(cmd) |
46 | | - try: |
47 | | - out = subprocess.Popen(cmd, stdout=subprocess.PIPE, |
48 | | - stderr=subprocess.PIPE, shell=True).communicate()[0] |
| 26 | + # for each node, build list of external and internal ips |
| 27 | + for node in node_list: |
| 28 | + describe_node = "kubectl describe node " + node + " " + kubeconfig |
| 29 | + out1, err1 = self.run_command(describe_node) |
| 30 | + ip_types = {} |
| 31 | + for line in out1.split("\n"): |
| 32 | + line1 = ' '.join(line.split()) |
| 33 | + if 'ExternalIP' in line1: |
| 34 | + parts = line1.split(":") |
| 35 | + nodeIP = parts[1].strip() |
| 36 | + ip_types["external"] = nodeIP |
| 37 | + if 'InternalIP' in line1: |
| 38 | + parts = line1.split(":") |
| 39 | + nodeIP = parts[1].strip() |
| 40 | + ip_types["internal"] = nodeIP |
| 41 | + node_ip_types.append(ip_types) |
49 | 42 |
|
50 | | - if out: |
51 | | - json_output = json.loads(out) |
52 | | - #print(json_output) |
53 | | - if 'tls' in json_output['spec']: |
54 | | - host = json_output['spec']['tls'][0]['hosts'][0] |
55 | | - appURL = "https://" + host.strip() |
56 | | - else: |
57 | | - host = json_output['spec']['rules'][0]['host'] |
58 | | - appURL = "http://" + host.strip() |
59 | | - break |
60 | | - except Exception as e: |
61 | | - print(e) |
62 | | - return appURL |
| 43 | + # prefer external ip; otherwise return internal ip |
| 44 | + for item in node_ip_types: |
| 45 | + if "external" in item: |
| 46 | + node_ips.append(item["external"]) |
| 47 | + elif "internal" in item: |
| 48 | + node_ips.append(item["internal"]) |
63 | 49 |
|
64 | | - def get_svc_port(self, svcs, namespace, kubeconfig): |
65 | | - nodePort = -1 |
66 | | - for svc in svcs: |
67 | | - cmd = 'kubectl get service ' + svc['Name'] + ' -n ' + svc['Namespace'] + ' -o json ' + kubeconfig |
68 | | - #print(cmd) |
69 | | - try: |
70 | | - out = subprocess.Popen(cmd, stdout=subprocess.PIPE, |
71 | | - stderr=subprocess.PIPE, shell=True).communicate()[0] |
| 50 | + return node_ips |
72 | 51 |
|
73 | | - if out: |
74 | | - json_output = json.loads(out) |
75 | | - #print(json_output) |
76 | | - service_type = json_output['spec']['type'] |
77 | | - if service_type == 'NodePort': |
78 | | - nodePort = json_output['spec']['ports'][0]['nodePort'] |
79 | | - #print("NodePort:" + str(nodePort)) |
80 | | - break |
81 | | - except Exception as e: |
82 | | - print(e) |
83 | | - return nodePort |
84 | 52 |
|
85 | | - def get_node_ip(self, kubeconfig): |
86 | | - cmd = 'kubectl describe node ' + kubeconfig |
87 | | - out = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).communicate()[0] |
88 | | - out = out.decode('utf-8') |
89 | | - #print("Node o/p:" + out) |
90 | | - for line in out.split("\n"): |
91 | | - if 'ExternalIP' in line: |
92 | | - parts = line.split(":") |
93 | | - nodeIP = parts[1].strip() |
94 | | - #print("Node IP:" + nodeIP) |
95 | | - return nodeIP |
96 | | - return "" |
| 53 | + def get_service_endpoints(self, kind, service_instance_name, kubeconfig): |
| 54 | + endpoints = [] |
| 55 | + service_name_in_annotation = self.get_service_name_from_ns(service_instance_name, kubeconfig) |
97 | 56 |
|
98 | | - def get_server_ip(self, kubeconfig): |
99 | | - server_ip = '' |
100 | | - parts = kubeconfig.split("=") |
101 | | - kcfg = parts[1].strip() |
102 | | - #print(parts) |
103 | | - fp = open(kcfg, "r") |
104 | | - #fp = open("/root/.kube/config", "r") |
105 | | - contents = fp.read() |
106 | | - content = '' |
107 | | - try: |
108 | | - content = json.loads(contents) |
109 | | - except: |
110 | | - content = yaml.safe_load(contents) |
| 57 | + if service_name_in_annotation.lower() != kind.lower(): |
| 58 | + print("Instance does not belong to the Service:" + kind) |
| 59 | + sys.exit(1) |
| 60 | + |
| 61 | + ingress_cmd = "kubectl get ingress -n " + service_instance_name + " " + kubeconfig |
| 62 | + |
| 63 | + out, err = self.run_command(ingress_cmd) |
| 64 | + if "No resources found" not in err: |
| 65 | + for line in out.split("\n"): |
| 66 | + line1 = ' '.join(line.split()) |
| 67 | + if 'NAME' not in line1 and line1 != '': |
| 68 | + parts = line1.split(" ") |
| 69 | + hostname = parts[2].strip() |
| 70 | + protocol = "https://" |
| 71 | + endpoint = protocol + hostname |
| 72 | + endpoints.append(endpoint) |
| 73 | + else: |
| 74 | + service_cmd = "kubectl get service -n " + service_instance_name + " " + kubeconfig |
| 75 | + out1, err1 = self.run_command(service_cmd) |
| 76 | + for line in out1.split("\n"): |
| 77 | + line1 = ' '.join(line.split()) |
| 78 | + endpoint = '' |
| 79 | + if 'NAME' not in line1 and line1 != '': |
| 80 | + parts = line1.split(" ") |
| 81 | + port_parts = parts[4].split(",") |
| 82 | + for protocol in port_parts: |
| 83 | + proto_ports = protocol.split(":") |
| 84 | + if len(proto_ports) == 2: |
| 85 | + proto_port = proto_ports[0].strip() |
| 86 | + app_port = (proto_ports[1].strip()).split("/")[0].strip() |
| 87 | + if parts[1] == 'LoadBalancer': |
| 88 | + if proto_port == '80': |
| 89 | + endpoint = "http://" + parts[2].strip() + ":" + app_port |
| 90 | + if proto_port == '443': |
| 91 | + endpoint = "https://" + parts[2].strip() + ":" + app_port |
| 92 | + if parts[1] == 'NodePort': |
| 93 | + ip_address_list = self._get_node_ips(kubeconfig) |
| 94 | + for ipaddr in ip_address_list: |
| 95 | + if proto_port == '80': |
| 96 | + endpoint = "http://" + ipaddr.strip() + ":" + app_port |
| 97 | + if proto_port == '443': |
| 98 | + endpoint = "https://" + ipaddr.strip() + ":" + app_port |
| 99 | + endpoints.append(endpoint) |
| 100 | + |
| 101 | + return endpoints |
111 | 102 |
|
112 | | - cluster_list = content['clusters'] |
113 | | - for cluster in cluster_list: |
114 | | - cluster_name = cluster['name'] |
115 | | - #print("Cluster name:" + cluster_name) |
116 | | - if cluster_name == 'kubeplus-saas-consumer' or cluster_name == 'kubeplus-saas-provider': |
117 | | - server_url = cluster['cluster']['server'] |
118 | | - #print(server_url) |
119 | | - server_url = server_url.strip() |
120 | | - parts = server_url.split(":") |
121 | | - server_ip = parts[1].strip() |
122 | | - #print(server_ip) |
123 | | - return server_ip |
124 | 103 |
|
125 | 104 | if __name__ == '__main__': |
126 | | - appURLFinder = AppURLFinder() |
127 | | - #crLogs.get_logs(sys.argv[1], sys.argv[2]) |
128 | | - #resources = sys.argv[1] |
129 | | - relation = sys.argv[1] |
130 | | - kind = sys.argv[2] |
131 | | - instance = sys.argv[3] |
132 | | - namespace = sys.argv[4] |
133 | | - kubeconfig = sys.argv[5] |
134 | | - #print(kind + " " + instance + " " + namespace + " " + kubeconfig) |
135 | | - resources = {} |
136 | | - if relation == 'connections': |
137 | | - resources = appURLFinder.get_resources_connections(kind, instance, namespace, kubeconfig) |
138 | | - #print(resources) |
139 | | - try: |
140 | | - ingresses = appURLFinder.get_ingresses(resources) |
141 | | - if len(ingresses) > 0: |
142 | | - appURL = appURLFinder.get_host_from_ingress(ingresses, namespace, kubeconfig) |
143 | | - print(appURL) |
144 | | - else: |
145 | | - svcs = appURLFinder.get_svc(resources) |
146 | | - svcPort = appURLFinder.get_svc_port(svcs, namespace, kubeconfig) |
147 | | - appIP = appURLFinder.get_node_ip(kubeconfig) |
148 | | - if appIP == "": |
149 | | - appIP = appURLFinder.get_server_ip(kubeconfig) |
150 | | - if appIP == '': |
151 | | - print("KubePlus SaaS Consumer context not found in the kubeconfig.") |
152 | | - print("Cannot form app url.") |
153 | | - exit() |
154 | | - else: |
155 | | - if "//" not in appIP: |
156 | | - appIP = "//" + appIP |
157 | | - appURL = "http:" + appIP + ":" + str(svcPort) |
158 | | - appURL = appURL.strip() |
159 | | - #print("App port:" + str(svcPort)) |
160 | | - print(appURL) |
161 | | - except Exception as e: |
162 | | - print(e) |
| 105 | + appURLFinder = AppURLFinder() |
| 106 | + kind = sys.argv[1] |
| 107 | + instance = sys.argv[2] |
| 108 | + kubeconfig = sys.argv[3] |
| 109 | + endpoints = appURLFinder.get_service_endpoints(kind, instance, kubeconfig) |
| 110 | + print(str(endpoints)) |
0 commit comments