2016-08-01 05:04:35 +00:00
|
|
|
# Copyright 2016 Canonical, Ltd.
|
|
|
|
#
|
|
|
|
# This program is free software: you can redistribute it and/or modify
|
|
|
|
# it under the terms of the GNU Affero General Public License as
|
|
|
|
# published by the Free Software Foundation, either version 3 of the
|
|
|
|
# License, or (at your option) any later version.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
# GNU Affero General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
2016-08-04 01:37:17 +00:00
|
|
|
import ipaddress
|
|
|
|
|
|
|
|
from probert.network import Network, NetworkInfo
|
2016-08-01 05:04:35 +00:00
|
|
|
|
|
|
|
IGNORED_DEVICE_TYPES = ['lo', 'tun', 'tap']
|
|
|
|
|
|
|
|
class Device:
|
|
|
|
# In general, an element of config['ethernets'] (or
|
|
|
|
# config['wifis']) matches an arbitrary set of interfaces. In
|
|
|
|
# subiquity, though, it just matches a single interface by
|
|
|
|
# name.
|
|
|
|
def __init__(self, name, vendor):
|
|
|
|
self.name = name
|
|
|
|
self.vendor = vendor
|
|
|
|
self.dhcp4 = False
|
|
|
|
self.dhcp6 = False
|
|
|
|
self.addresses = []
|
|
|
|
|
|
|
|
@classmethod
|
2016-08-04 01:37:17 +00:00
|
|
|
def from_probe_data(cls, network, info):
|
|
|
|
device = cls(info.name, info.vendor)
|
|
|
|
hasipv4, hasipv6 = False, False
|
|
|
|
ip = network.get_ips(info.name)
|
|
|
|
if ip is not None:
|
|
|
|
addr = ip['addr']
|
|
|
|
mask = ip['netmask']
|
|
|
|
address = ipaddress.ip_interface(addr + '/' + mask)
|
|
|
|
if address.version == 4:
|
|
|
|
hasipv4 = True
|
|
|
|
if address.version == 6:
|
|
|
|
hasipv6 = True
|
|
|
|
device.addresses.append(address)
|
|
|
|
if hasipv4:
|
|
|
|
device.dhcp4 = True
|
|
|
|
if hasipv6:
|
|
|
|
device.dhcp6 = True
|
|
|
|
return device
|
2016-08-01 05:04:35 +00:00
|
|
|
|
|
|
|
def render(self):
|
|
|
|
addresses = []
|
|
|
|
for address in self.addresses:
|
|
|
|
if address.version == 4 and not self.dhcp4:
|
2016-08-04 02:28:59 +00:00
|
|
|
addresses.append(address.with_prefixlen)
|
2016-08-01 05:04:35 +00:00
|
|
|
if address.version == 6 and not self.dhcp6:
|
2016-08-04 02:28:59 +00:00
|
|
|
addresses.append(address.with_prefixlen)
|
2016-08-01 05:04:35 +00:00
|
|
|
data = {
|
|
|
|
'dhcp4': str(self.dhcp4).lower(),
|
|
|
|
'dhcp4': str(self.dhcp4).lower(),
|
|
|
|
}
|
|
|
|
if addresses:
|
|
|
|
data['addresses'] = addresses
|
|
|
|
return data
|
|
|
|
|
|
|
|
class PhysicalDevice(Device):
|
|
|
|
pass
|
|
|
|
|
|
|
|
class EthernetDevice(PhysicalDevice):
|
|
|
|
pass
|
|
|
|
|
|
|
|
## class WifiDevice(PhysicalDevice):
|
|
|
|
## ## lots of things go here
|
|
|
|
|
|
|
|
## class BridgeDevice(Device):
|
|
|
|
## def __init__(self, name):
|
|
|
|
## Device.__init__(name)
|
|
|
|
## self.interfaces = []
|
|
|
|
|
|
|
|
class NetworkConfig:
|
|
|
|
def __init__(self):
|
|
|
|
self.ethernets = {}
|
|
|
|
## self.wifis = {}
|
|
|
|
## self.bridges = {}
|
|
|
|
|
|
|
|
def render(self):
|
|
|
|
ethernets = {}
|
2016-08-04 01:37:17 +00:00
|
|
|
for ethernet in self.ethernets.values():
|
|
|
|
ethernets[ethernet.name] = ethernet.render()
|
2016-08-01 05:04:35 +00:00
|
|
|
data = {
|
|
|
|
'version': 2,
|
|
|
|
}
|
|
|
|
if ethernets:
|
|
|
|
data['ethernets'] = ethernets
|
2016-08-04 01:37:17 +00:00
|
|
|
return {'network': data}
|
2016-08-01 05:04:35 +00:00
|
|
|
|
|
|
|
@classmethod
|
2016-08-04 01:37:17 +00:00
|
|
|
def from_probe_data(cls, results):
|
|
|
|
config = cls()
|
|
|
|
network = Network(results)
|
|
|
|
for name, data in network.results['network'].items():
|
2016-08-01 05:04:35 +00:00
|
|
|
type = data['type']
|
|
|
|
if type in IGNORED_DEVICE_TYPES:
|
|
|
|
continue
|
|
|
|
if data['bridge']['is_bridge']:
|
|
|
|
pass ## bridges not yet supported
|
2016-08-04 01:37:17 +00:00
|
|
|
elif data['bond']['is_master']:
|
2016-08-01 05:04:35 +00:00
|
|
|
pass ## bridges not yet supported
|
|
|
|
if type == 'eth':
|
2016-08-04 01:37:17 +00:00
|
|
|
info = NetworkInfo({name:data})
|
|
|
|
config.ethernets[name] = EthernetDevice.from_probe_data(network, info)
|
|
|
|
return config
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
import sys, json, yaml
|
|
|
|
data = json.load(open(sys.argv[1]))
|
|
|
|
config = NetworkConfig.from_probe_data(data)
|
|
|
|
print(yaml.dump(config.render()))
|