def getNetworkConfigWifi(update, name, cfg, iface): # Claim a subnet for this interface from the pool. subnet = networkPool.next() hosts = subnet.hosts() # Generate internal (in the chute) and external (in the host) # addresses. # # Example: # subnet: 192.168.30.0/24 # netmask: 255.255.255.0 # external: 192.168.30.1 # internal: 192.168.30.2 iface['subnet'] = subnet iface['netmask'] = str(subnet.netmask) iface['externalIpaddr'] = str(hosts.next()) iface['internalIpaddr'] = str(hosts.next()) # Generate the internal IP address with prefix length (x.x.x.x/y) for # convenience of other code that expect that format (e.g. pipework). iface['ipaddrWithPrefix'] = "{}/{}".format( iface['internalIpaddr'], subnet.prefixlen) # Generate initial portion (prefix) of interface name. # # NOTE: We add a "v" in front of the interface name to avoid triggering # the udev persistent net naming rules, which are hard-coded to certain # typical strings such as "eth*" and "wlan*" but not "veth*" or # "vwlan*". We do NOT want udev renaming our virtual interfaces. iface['extIntfPrefix'] = "v" + iface['device'] + "." iface['extIntfNumber'] = interfaceNumberPool.next() # Generate a name for the new interface in the host. iface['externalIntf'] = "{}{:04x}".format( iface['extIntfPrefix'], iface['extIntfNumber']) if len(iface['externalIntf']) > MAX_INTERFACE_NAME_LEN: out.warn("Interface name ({}) is too long\n". format(iface['externalIntf'])) raise Exception("Interface name is too long") # Add extra fields for WiFi devices. if cfg['type'] == "wifi": # Check for required fields. res = pdutils.check(cfg, dict, ['ssid']) if res: out.warn('WiFi network interface definition {}\n'.format(res)) raise Exception("Interface definition missing field(s)") iface['ssid'] = cfg['ssid'] # Optional encryption settings getWifiKeySettings(cfg, iface) # Give a warning if the dhcp block is missing, since it is likely # that developers will want a DHCP server to go with their AP. if 'dhcp' not in cfg: out.warn("No dhcp block found for interface {}; " "will not run a DHCP server".format(name))
def installChute(host, port, config): ''' Take a local config yaml file and launch chute of given host with pdfcd running on specified port. ''' # Read local yaml into a config_json to send via post request try: with open(config, 'r') as stream: config_json = yaml.load(stream) config_json['date'] = config_json['date'].isoformat() except IOError as e: print 'Error: ' + config + ' not found.' return # Verify the config provided in some way. cfg_verf = pdutils.check(config_json, dict, {'dockerfile': dict, 'name': str, 'owner': str}) if cfg_verf: print 'ERROR: ' + cfg_verf return # Only allowed one way to provide a dockerfile order is local, remote, inline if 'local' in config_json['dockerfile']: with open(config_json['dockerfile']['local'], 'r') as stream: config_json['dockerfile'] = stream.read() elif 'remote' in config_json['dockerfile']: print 'Remote Dockerfile not supported yet.' return elif 'inline' in config_json['dockerfile']: config_json['dockerfile'] = config_json['dockerfile']['inline'] else: print 'ERROR: No Dockerfile specified in config file.' return print 'Installing chute...\n' params = {'config': config_json} r = requests.post('http://' + host + ':' + str(port) + '/v1/chute/create', data=json.dumps(params), stream=True) for line in r.iter_lines(): if line: try: line = json.loads(line) if line.get('success'): print line.get('message') else: print 'ERROR: Failed to install chute.(' + urllib.unquote(str(line.get('message'))) + ')' except Exception as e: print line
def getNetworkConfig(update): """ For the Chute provided, return the dict object of a 100% filled out configuration set of network configuration. This would include determining what the IP addresses, interfaces names, etc... """ # Notes: # # Fill in the gaps of knowledge between what the dev provided us in their # config and what would be required to add all the config changes to get # the chute working By the end of this function there should be a # cache:networkInterfaces key containing a list of dictionary objects for # each interface we will need to create, including netmasks IP addresses, # etc.. this is important to allow all other modules to know what the IP # addr is for this chute, etc.. # # old code under lib.internal.chs.chutelxc same function name interfaces = list() # Put the list in the cache now (shared reference), so that if we fail out # of this function after partial completion, the abort function can take # care of what made it into the list. update.new.setCache('networkInterfaces', interfaces) if not hasattr(update.new, 'net'): return None # Make a dictionary of old interfaces. Any new interfaces that are # identical to an old one do not need to be changed. oldInterfaces = dict() if update.old is not None: cachedInterfaces = update.old.getCache('networkInterfaces') oldInterfaces = {iface['name']: iface for iface in cachedInterfaces} devices = update.new.getCache('networkDevices') devIters = {t: itertools.cycle(devices[t]) for t in devices.keys()} for name, cfg in update.new.net.iteritems(): # Check for required fields. res = pdutils.check(cfg, dict, ['intfName', 'type']) if res: out.warn('Network interface definition {}\n'.format(res)) raise Exception("Interface definition missing field(s)") iface = { 'name': name, # Name (not used?) 'netType': cfg['type'], # Type (wan, lan, wifi) 'internalIntf': cfg['intfName'] # Interface name in chute } if iface['name'] in oldInterfaces: oldIface = oldInterfaces[iface['name']] if interfaceDefsEqual(iface, oldIface): # If old interface is the same, then keep it and move on. interfaces.append(oldIface) continue # Try to find a physical device of the requested type. # # Note: we try this first because it can fail, and then we will not try # to allocate any resources for it. try: device = devIters[cfg['type']].next() iface['device'] = device['name'] except (KeyError, StopIteration): out.warn("Request for {} device cannot be fulfilled". format(cfg['type'])) raise Exception("Missing device(s) requested by chute") if cfg['type'] == "wifi": getNetworkConfigWifi(update, name, cfg, iface) # Pass on DHCP configuration if it exists. if 'dhcp' in cfg: iface['dhcp'] = cfg['dhcp'] interfaces.append(iface) update.new.setCache('networkInterfaces', interfaces)
def getVirtDHCPSettings(update): """ Looks at the runtime rules the developer defined to see if they want a dhcp server. If so it generates the data and stores it into the chute cache key:virtDHCPSettings. """ interfaces = update.new.getCache('networkInterfaces') if interfaces is None: return dhcpSettings = list() for iface in interfaces: # Only look at interfaces with DHCP server requested. if 'dhcp' not in iface: continue dhcp = iface['dhcp'] # Check for required fields. res = pdutils.check(dhcp, dict, ['lease', 'start', 'limit']) if(res): out.warn('DHCP server definition {}\n'.format(res)) raise Exception("DHCP server definition missing field(s)") # NOTE: Having one dnsmasq section for each interface deviates from how # OpenWRT does things, where they assume a single instance of dnsmasq # will be handling all DHCP and DNS needs. config = {'type': 'dnsmasq'} options = {} uciutils.setList(options, 'interface', [iface['externalIntf']]) # Optional: developer can pass in a list of DNS nameservers to use # instead of the system default. # # This path -> clients query our dnsmasq server; dnsmasq uses the # specified nameservers and caches the results. if DNSMASQ_CACHE_ENABLED and 'dns' in dhcp: options['noresolv'] = '1' uciutils.setList(options, 'server', dhcp['dns']) dhcpSettings.append((config, options)) config = {'type': 'dhcp', 'name': iface['externalIntf']} options = { 'interface': iface['externalIntf'], 'start': dhcp['start'], 'limit': dhcp['limit'], 'leasetime': dhcp['lease'], } # This option tells clients that the router is the interface inside the # chute not the one in the host. uciutils.setList(options, 'dhcp_option', ["option:router,{}".format( iface['internalIpaddr'])]) # Optional: developer can pass in a list of DNS nameservers to use # instead of the system default. # # This path -> clients receive the list of DNS servers and query them # directly. if not DNSMASQ_CACHE_ENABLED and 'dns' in dhcp: uciutils.appendListItem(options, 'dhcp_option', ",".join(["option:dns-server"] + dhcp['dns'])) dhcpSettings.append((config, options)) update.new.setCache('virtDHCPSettings', dhcpSettings)