def get_address(self, get_address_cmd, cwd): ''' In the event of having to start a controller without the knowledge of its IP address a priori, periodically attempt to retrieve the IP from the output of get_address_cmd. If multiple controller instances are launched in this case, only the designated address retriever makes such attempts. ''' if get_address_cmd is "": raise RuntimeError("Controller address cannot be resolved!") for _ in range(self._max_address_retrieval_attempts): # If another controller instance is already retrieving address, back off and wait if self._address_retriever is None or self._address_retriever == self.label: ControllerConfig._address_retriever = self.label p = subprocess.Popen(get_address_cmd, shell=True, stdout=subprocess.PIPE, cwd=cwd) (new_addresses, _) = p.communicate() new_addresses = new_addresses.strip() new_addresses = re.split("\s+", new_addresses) new_addresses = [a for a in new_addresses if address_is_ip(a)] self._controller_addresses.extend(new_addresses) if len(self._controller_addresses) != 0: break log.warn("Controller addresses not found... Keep trying.") time.sleep(5.0) else: raise RuntimeError("Cannot retrieve controller IP addresses after %d attempts!" % self._max_address_retrieval_attempts) address = None if self.index is not None and self.index <= len(self._controller_addresses): address = self._controller_addresses[self.index-1] self.address = address log.info("Found controller address for %s: %s!" % (self.label, self.address)) else: raise RuntimeError("No IP address resolved for controller %s!" % self.label) return address
def get_address(self, get_address_cmd, cwd): ''' In the event of having to start a controller without the knowledge of its IP address a priori, periodically attempt to retrieve the IP from the output of get_address_cmd. If multiple controller instances are launched in this case, only the designated address retriever makes such attempts. ''' if get_address_cmd is "": raise RuntimeError("Controller address cannot be resolved!") for _ in range(self._max_address_retrieval_attempts): # If another controller instance is already retrieving address, back off and wait if self._address_retriever is None or self._address_retriever == self.label: ControllerConfig._address_retriever = self.label p = subprocess.Popen(get_address_cmd, shell=True, stdout=subprocess.PIPE, cwd=cwd) (new_addresses, _) = p.communicate() new_addresses = new_addresses.strip() new_addresses = re.split("\s+", new_addresses) new_addresses = [a for a in new_addresses if address_is_ip(a)] self._controller_addresses.extend(new_addresses) if len(self._controller_addresses) != 0: break log.warn("Controller addresses not found... Keep trying.") time.sleep(5.0) else: raise RuntimeError( "Cannot retrieve controller IP addresses after %d attempts!" % self._max_address_retrieval_attempts) address = None if self.index is not None and self.index <= len( self._controller_addresses): address = self._controller_addresses[self.index - 1] self.address = address log.info("Found controller address for %s: %s!" % (self.label, self.address)) else: raise RuntimeError("No IP address resolved for controller %s!" % self.label) return address
def __init__(self, start_cmd="", address="127.0.0.1", port=None, additional_ports={}, cwd=None, sync=None, controller_type=None, label=None, config_file=None, config_template=None, try_new_ports=False, kill_cmd="", restart_cmd="", get_address_cmd="", launch_in_network_namespace=False, snapshot_address=""): ''' Store metadata for the controller. - start_cmd: command that starts a controller or a set of controllers, followed by a list of command line tokens as arguments. You may make use of two macros: __address__ expands to some available IP address for the controller, and __port__ expands to some available (OpenFlow) port. - kill_cmd: command that kills a controller or a set of controllers, followed by a list of command line tokens as arguments - address, port: controller socket info for listening to OpenFlow connections from switches. address may be specified as "auto" to automatically find a non-localhost IP address in the range 192.168.1.0/24, or "__address__" to use get_address_cmd to choose an address. - get_address_cmd: an optional bash command that returns an address for the controller to bind to. - controller_type: controller type, specified by the corresponding Controller class itself, or a string chosen from one of the keys in controller_type_map - snapshot_address: path to unix domain socket where (if configured) controller will be listening for snapshot commands ''' if start_cmd == "": raise RuntimeError("Must specify boot parameters.") self.start_cmd = start_cmd self.kill_cmd = kill_cmd self.restart_cmd = restart_cmd self.launch_in_network_namespace = launch_in_network_namespace self.snapshot_address = snapshot_address if launch_in_network_namespace and (address == "127.0.0.1" or address == "localhost"): raise ValueError( """Must set a non-localhost address for namespace controller.\n""" """Specify `auto` to automatically find an available IP.""") # Set label if label is None: label = "c%s" % str(self._controller_count_gen.next()) if label in self._controller_labels: raise ValueError("Label %s already registered!" % label) self._controller_labels.add(label) self.label = label # Set index, for assigning IP addresses in the case of multiple controllers match = re.search("c(\d+)", self.label) if match: self.index = int(match.groups()[0]) else: self.index = None # Set address. if address == "__address__": address = self.get_address(get_address_cmd, cwd) elif address == "auto": # TODO(cs): need to add support for auto to the sync uri. address = IPAddressSpace.find_unclaimed_address() self.address = address IPAddressSpace.register_address(address) if address_is_ip(address) or address == "localhost": # Normal TCP socket if not port: port = self._port_gen[address].next() if try_new_ports: port = find_port(xrange(port, port + 2000)) self.port = port self._server_info = (self.address, port) else: # Unix domain socket self.port = None self._server_info = address self.controller_type = controller_type if controller_type is None: for t in controller_type_map.keys(): if t in self.start_cmd: self.controller_class = controller_type_map[t] break else: # Default to Base Controller class self.controller_class = Controller else: if controller_type not in controller_type_map.keys(): raise RuntimeError("Unknown controller type: %s" % controller_type) self.controller_class = controller_type_map[controller_type] self.cwd = cwd if not cwd: sys.stderr.write(""" ======================================================================= WARN - no working directory defined for controller with command line %s The controller is run in the STS base directory. This may result in unintended consequences (i.e. controller not logging correctly). ======================================================================= \n""" % (self.start_cmd)) self.sync = sync self.config_file = config_file self.config_template = config_template self.additional_ports = additional_ports
def __init__(self, start_cmd="", address="127.0.0.1", port=None, additional_ports={}, cwd=None, sync=None, controller_type=None, label=None, config_file=None, config_template=None, try_new_ports=False, kill_cmd="", restart_cmd="", get_address_cmd="", launch_in_network_namespace=False): ''' Store metadata for the controller. - start_cmd: command that starts a controller or a set of controllers, followed by a list of command line tokens as arguments. You may make use of two macros: __address__ expands to some available IP address for the controller, and __port__ expands to some available (OpenFlow) port. - kill_cmd: command that kills a controller or a set of controllers, followed by a list of command line tokens as arguments - address, port: controller socket info for listening to OpenFlow connections from switches. address may be specified as "auto" to automatically find a non-localhost IP address in the range 192.168.1.0/24, or "__address__" to use get_address_cmd to choose an address. - get_address_cmd: an optional bash command that returns an address for the controller to bind to. - controller_type: controller type, specified by the corresponding Controller class itself, or a string chosen from one of the keys in controller_type_map ''' if start_cmd == "": raise RuntimeError("Must specify boot parameters.") self.start_cmd = start_cmd self.kill_cmd = kill_cmd self.restart_cmd = restart_cmd self.launch_in_network_namespace = launch_in_network_namespace if launch_in_network_namespace and (address == "127.0.0.1" or address == "localhost"): raise ValueError("""Must set a non-localhost address for namespace controller.\n""" """Specify `auto` to automatically find an available IP.""") # Set label if label is None: label = "c%s" % str(self._controller_count_gen.next()) if label in self._controller_labels: raise ValueError("Label %s already registered!" % label) self._controller_labels.add(label) self.label = label # Set index, for assigning IP addresses in the case of multiple controllers match = re.search("c(\d+)", self.label) if match: self.index = int(match.groups()[0]) else: self.index = None # Set address. if address == "__address__": address = self.get_address(get_address_cmd, cwd) elif address == "auto": # TODO(cs): need to add support for auto to the sync uri. address = IPAddressSpace.find_unclaimed_address() self.address = address IPAddressSpace.register_address(address) if address_is_ip(address) or address == "localhost": # Normal TCP socket if not port: port = self._port_gen[address].next() if try_new_ports: port = find_port(xrange(port, port+2000)) self.port = port self._server_info = (self.address, port) else: # Unix domain socket self.port = None self._server_info = address self.controller_type = controller_type if controller_type is None: for t in controller_type_map.keys(): if t in self.start_cmd: self.controller_class = controller_type_map[t] break else: # Default to Base Controller class self.controller_class = Controller else: if controller_type not in controller_type_map.keys(): raise RuntimeError("Unknown controller type: %s" % controller_type) self.controller_class = controller_type_map[controller_type] self.cwd = cwd if not cwd: sys.stderr.write(""" ======================================================================= WARN - no working directory defined for controller with command line %s The controller is run in the STS base directory. This may result in unintended consequences (i.e. controller not logging correctly). ======================================================================= \n""" % (self.start_cmd) ) self.sync = sync self.config_file = config_file self.config_template = config_template self.additional_ports = additional_ports