#!/usr/bin/env python import argparse import base64 import json import os from os.path import expanduser import sys import tempfile import urllib import yaml import requests from pprint import pprint def _get_session_from_kubeconfig(): kubeconfig = expanduser('~/.kube/config') with open(kubeconfig, 'r') as f: conf = yaml.safe_load(f.read()) for context in conf['contexts']: if context['name'] == conf['current-context']: current_context = context break cluster_name = current_context['context']['cluster'] for cluster in conf['clusters']: if cluster['name'] == cluster_name: current_cluster = cluster break server = current_cluster['cluster']['server'] if server.startswith('https'): ca_cert_data = current_cluster['cluster']['certificate-authority-data'] for user in conf['users']: if user['name'] == current_context['context']['user']: current_user = user break client_cert_data = current_user['user']['client-certificate-data'] client_key_data = current_user['user']['client-key-data'] client_cert_file = tempfile.NamedTemporaryFile(delete=False) client_key_file = tempfile.NamedTemporaryFile(delete=False) ca_cert_file = tempfile.NamedTemporaryFile(delete=False) client_cert_file.write(base64.decodebytes(client_cert_data.encode())) client_cert_file.close() client_key_file.write(base64.decodebytes(client_key_data.encode())) client_key_file.close() ca_cert_file.write(base64.decodebytes(ca_cert_data.encode())) ca_cert_file.close() session = requests.Session() session.cert = (client_cert_file.name, client_key_file.name) session.verify = ca_cert_file.name else: session = requests.Session() return session, server def get(args): session, server = _get_session_from_kubeconfig() namespace = os.getenv('KUBECTL_PLUGINS_CURRENT_NAMESPACE') if args.resource in ('vif', 'vifs'): vifs(session, server, namespace, args) def _vif_formatted_output(vif_data, wide=False): max_len = 12 padding = 4 vif_data.insert(0, {'pod_name': 'POD NAME', 'vif_name': 'VIF NAME', 'host_ip': 'HOST IP', 'plugin': 'BINDING', 'active': 'ACTIVE', 'address': 'IP ADDRESS', 'port_id': 'PORT ID', 'mac_address': 'MAC ADDRESS', 'vlan_id': 'VLAN'}) short_format = ('{pod_name:{tab_len:d}s} {vif_name:{tab_len:d}s} ' '{plugin:10s} {address:{tab_len:d}s} {vlan_id:4}') long_format = ('{pod_name:{tab_len:d}s} {vif_name:{tab_len:d}s} ' '{plugin:10s} {address:{tab_len:d}s} {vlan_id:4} ' '{active:6} {host_ip:{tab_len:d}s} ' '{mac_address:{tab_len:d}s} {port_id:{tab_len:d}s}') for vif in vif_data: active = vif['active'] if type(active) == bool: vif['active'] = 'yes' if active else 'no' if 'vlan_id' not in vif: vif['vlan_id'] = '' if wide: print(long_format.format(tab_len=max_len+padding, **vif)) else: print(short_format.format(tab_len=max_len+padding, **vif)) def vifs(session, server, namespace, args): url = '%s/api/v1/namespaces/%s/pods' % (server, namespace) selector = os.getenv('KUBECTL_PLUGINS_LOCAL_FLAG_SELECTOR') if selector: url += '?labelSelector=' + urllib.quote(selector) output = os.getenv('KUBECTL_PLUGINS_LOCAL_FLAG_OUTPUT') response = session.get(url) if response.ok: pods = response.json() else: sys.stderr.write('Failed to retrieve pod data') sys.exit(1) vif_data = [] for pod in pods['items']: data = {'pod_name': pod['metadata']['name']} if 'hostIP' in pod['status']: data['host_ip'] = pod['status']['hostIP'] vif = pod['metadata']['annotations'].get('openstack.org/kuryr-vif') if vif is None: continue # not kuryr annotated else: vif = json.loads(vif) if vif['versioned_object.name'] == 'PodState': # This is new format, fetch only default_vif from there. vif = vif['versioned_object.data']['default_vif'] network = (vif['versioned_object.data']['network'] ['versioned_object.data']) first_subnet = (network['subnets']['versioned_object.data'] ['objects'][0]['versioned_object.data']) first_subnet_ip = (first_subnet['ips']['versioned_object.data'] ['objects'][0]['versioned_object.data']['address']) first_subnet_prefix = first_subnet['cidr'].split('/')[1] data['vif_name'] = vif['versioned_object.data']['vif_name'] data['plugin'] = vif['versioned_object.data']['plugin'] data['active'] = vif['versioned_object.data']['active'] data['address'] = '%s/%s' % (first_subnet_ip, first_subnet_prefix) data['port_id'] = vif['versioned_object.data']['id'] data['mac_address'] = vif['versioned_object.data']['address'] vlan_id = vif['versioned_object.data'].get('vlan_id') if vlan_id is not None: data['vlan_id'] = vlan_id vif_data.append(data) if output == 'json': pprint(vif_data) elif output == 'tabular': _vif_formatted_output(vif_data) elif output == 'wide': _vif_formatted_output(vif_data, wide=True) else: sys.stderr.write('Unrecognized output format') sys.exit(1) if __name__ == '__main__': parser = argparse.ArgumentParser(usage='kuryr [command] [options]') subparsers = parser.add_subparsers(title='Available commands', metavar='') get_parser = subparsers.add_parser( 'get', usage='kuryr get [resource] [options]', help='Gets Kuryr managed resource information.') get_parser.add_argument( 'resource', action='store', choices=('vif',), help='Resource to return info for.') get_parser.set_defaults(func=get) args = parser.parse_args() args.func(args)