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