pyveth - veth driver for Docker Engine written in Python
Jacek Kowalski
2020-05-04 8c0fc507499360bce22bd30a1edb1d0c81ffe1f9
commit | author | age
f973b9 1 import ipaddress
JK 2 import random
3
4 import flask
5 import pyroute2
6 from docker_plugin_api.NetworkDriverEntities import *
7 from docker_plugin_api.Plugin import Blueprint, InputValidationException
8
9 from .NetworkDriverData import *
10
11 app = Blueprint('NetworkDriver', __name__)
12
13
14 def genid(size=8, chars='0123456789abcdef'):
15     return ''.join([random.choice(chars) for _ in range(size)])
16
17
8c0fc5 18 def create_interface(endpoint, network) -> str:
f973b9 19     ifname0 = 'veth{}'.format(genid())
JK 20     ifname1 = 'veth{}'.format(genid())
8c0fc5 21
f973b9 22     with pyroute2.IPRoute() as ip:
JK 23         ip.link('add', ifname=ifname0, peer=ifname1, kind='veth')
24         idx = ip.link_lookup(ifname=ifname0)[0]
25         if endpoint.Interface.MacAddress:
26             ip.link('set', index=idx, address=endpoint.Interface.MacAddress)
27         ip.link('set', index=idx, state='up')
28         if endpoint.Interface.Address:
29             addr = ipaddress.ip_interface(endpoint.Interface.Address)
30             ip.addr('add', index=idx, address=addr.ip.compressed, mask=addr.network.prefixlen)
31         if endpoint.Interface.AddressIPv6:
32             addr = ipaddress.ip_interface(endpoint.Interface.AddressIPv6)
33             ip.addr('add', index=idx, address=addr.ip.compressed, mask=addr.network.prefixlen)
34         endpoint.Interface.Name = ifname0
35
36         idx = ip.link_lookup(ifname=ifname1)[0]
37         ip.link('set', index=idx, state='up')
38         if 'parent' in network.Options:
39             id_parent = ip.link_lookup(ifname=network.Options['parent'])[0]
40             print(ip.link("set", index=idx, master=id_parent))
41         endpoint.Interface.Peer = ifname1
42
8c0fc5 43     return ifname0
JK 44
45
46 @app.route('/NetworkDriver.GetCapabilities', methods=['POST'])
47 def GetCapabilities():
48     return {
49         'Scope': 'local',
50         'ConnectivityScope': 'global',
51     }
52
53
54 @app.route('/NetworkDriver.CreateNetwork', methods=['POST'])
55 def CreateNetwork():
56     network = NetworkCreateEntity(**flask.request.get_json(force=True))
57     try:
58         for option, value in network.Options['com.docker.network.generic'].items():
59             if option not in network.Options:
60                 network.Options[option] = value
61     except KeyError:
62         pass
63     networks[network.NetworkID] = network
64     networks_sync()
65     return {}
66
67
68 @app.route('/NetworkDriver.DeleteNetwork', methods=['POST'])
69 def DeleteNetwork():
70     network = NetworkDeleteEntity(**flask.request.get_json(force=True))
71     if network.NetworkID in networks:
72         del networks[network.NetworkID]
73         networks_sync()
74     return {}
75
76
77 @app.route('/NetworkDriver.CreateEndpoint', methods=['POST'])
78 def CreateEndpoint():
79     endpoint = EndpointCreateEntity(**flask.request.get_json(force=True))
80     endpoints['{}-{}'.format(endpoint.NetworkID, endpoint.EndpointID)] = endpoint
81     return {
82         'Interface': {
83         }
84     }
85
86
87 @app.route('/NetworkDriver.EndpointOperInfo', methods=['POST'])
88 def EndpointOperInfo():
89     endpoint = EndpointOperInfoEntity(**flask.request.get_json(force=True))
90     return {
91         'Value': {
92         }
93     }
94
95
96 @app.route('/NetworkDriver.DeleteEndpoint', methods=['POST'])
97 def DeleteEndpoint():
98     entity = EndpointDeleteEntity(**flask.request.get_json(force=True))
99     endpoint_id = '{}-{}'.format(entity.NetworkID, entity.EndpointID)
100     if endpoint_id in endpoints:
101         del endpoints['{}-{}'.format(entity.NetworkID, entity.EndpointID)]
102     return {}
103
104
105 @app.route('/NetworkDriver.Join', methods=['POST'])
106 def Join():
107     join = JoinEntity(**flask.request.get_json(force=True))
108     network = networks[join.NetworkID]
109     endpoint = endpoints['{}-{}'.format(join.NetworkID, join.EndpointID)]
110
111     interface = create_interface(endpoint, network)
112
f973b9 113     gw4 = None
JK 114     for net4 in network.IPv4:
115         try:
116             gw4 = ipaddress.ip_interface(net4.Gateway)
117             break
118         except:
119             pass
120     gw6 = None
121     for net6 in network.IPv6:
122         try:
123             gw6 = ipaddress.ip_interface(net6.Gateway)
124             break
125         except:
126             pass
127
128     result = {
129         'InterfaceName': {
8c0fc5 130             'SrcName': interface,
f973b9 131             'DstPrefix': 'eth',
JK 132         },
133     }
134     if gw4 is not None:
135         result['Gateway'] = gw4.ip.compressed
136     if gw6 is not None:
137         result['GatewayIPv6'] = gw6.ip.compressed
138     return result
139
140
141 @app.route('/NetworkDriver.Leave', methods=['POST'])
142 def Leave():
143     leave = LeaveEntity(**flask.request.get_json(force=True))
144     return {}
145
146
147 @app.route('/NetworkDriver.DiscoverNew', methods=['POST'])
148 def DiscoverNew():
149     entity = DiscoverNewEntity(**flask.request.get_json(force=True))
150     return {}
151
152
153 @app.route('/NetworkDriver.DiscoverDelete', methods=['POST'])
154 def DiscoverDelete():
155     entity = DiscoverDeleteEntity(**flask.request.get_json(force=True))
156     return {}
157
158
159 @app.route('/NetworkDriver.ProgramExternalConnectivity', methods=['POST'])
160 def ProgramExternalConnectivity():
161     entity = ProgramExternalConnectivityEntity(**flask.request.get_json(force=True))
162     return {}
163
164
165 @app.route('/NetworkDriver.RevokeExternalConnectivity', methods=['POST'])
166 def RevokeExternalConnectivity():
167     entity = RevokeExternalConnectivityEntity(**flask.request.get_json(force=True))
168     return {}