def from_cli_options(cls, domains, access_key_id, access_key_secret, type): """ Construct a Config object from a set of given configurations Args: domains: domains to update access_key_id: access key id provided by api provider access_key_secret: access key secret provided by api provider type: dns record type, for now only 'A' is supported Returns: Instance of Config """ if not domains or not access_key_id or not access_key_secret: DDNSUtils.err_and_exit("Aruguments are not sufficient: domains, access_key_id and access_key_secret") apiProviderInfo = ApiProviderInfo(access_key_id, access_key_secret) records = [] try: for fullDomain in domains: record = DomainSection.from_full_domain(fullDomain, type) records.append(record) config = cls(apiProviderInfo, records) return config except ValueError as ex: DDNSUtils.err_and_exit("Invalid parameters in config: {0}".format(ex))
def __init__(self): # default options self.debug = False self.interval = 600 self.access_id = None self.access_key = None self.parser = ConfigParser.ConfigParser() if not self.parser.read(CONF_FILE): # Compaitible consideration for v0.1 if not self.parser.read(SYS_CONF_FILE): DDNSUtils.err_and_exit("Failed to read config file.") try: self.debug = self.parser.getboolean("DEFAULT", "debug") self.access_id = self.parser.get("DEFAULT", "access_id") self.access_key = self.parser.get("DEFAULT", "access_key") except ValueError as ex: DDNSUtils.err_and_exit("Invalid debug in config: {0}".format(ex)) except ConfigParser.NoSectionError as ex: DDNSUtils.err_and_exit("Invalid config: {0}".format(ex)) except ConfigParser.NoOptionError as ex: DDNSUtils.err_and_exit("Invalid config: {0}".format(ex)) if not self.access_id or not self.access_key: DDNSUtils.err_and_exit( "Invalid access_id or access_key in config file.")
def main(): """ Main routine """ config = DDNSConfig() record_manager = DDNSDomainRecordManager(config) # get current public ip for this server if config.pifn_enable: current_public_ip = DDNSUtils.get_interface_address( config.pifn_interface) else: current_public_ip = DDNSUtils.get_current_public_ip() if not current_public_ip: DDNSUtils.err_and_exit("Failed to get current public IP") for local_record in record_manager.local_record_list: if local_record.subdomain == '*': dns_resolved_ip = DDNSUtils.get_dns_resolved_ip( 'xxx', local_record.domainname) else: dns_resolved_ip = DDNSUtils.get_dns_resolved_ip( local_record.subdomain, local_record.domainname) if local_record.type == "AAAA": current_ip = DDNSUtils.get_interface_ipv6_address( local_record.interface) else: current_ip = current_public_ip if current_ip == dns_resolved_ip: DDNSUtils.info("Skipped as no changes for DomainRecord" \ "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record)) continue # If current public IP doesn't equal to current DNS resolved ip, only in three cases: # 1. The new synced IP for remote record in Aliyun doesn't take effect yet # 2. remote record's IP in Aliyun server has changed # 3. current public IP is changed remote_record = record_manager.fetch_remote_record(local_record) if not remote_record: DDNSUtils.err("Failed finding remote DomainRecord" \ "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record)) continue if current_ip == remote_record.value: DDNSUtils.info("Skipped as we already updated DomainRecord" \ "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record)) continue # if we can fetch remote record and record's value doesn't equal to public IP sync_result = record_manager.update(remote_record, current_ip, local_record.type) if not sync_result: DDNSUtils.err("Failed updating DomainRecord" \ "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record)) else: DDNSUtils.info("Successfully updated DomainRecord" \ "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record))
def validate(self): if not self.accessId or not self.accessKey: DDNSUtils.err_and_exit("Invalid access_id or access_key in config file.") for rec in self.localDomainRecordList: if not rec.domain or not rec.subDomain or not rec.type: DDNSUtils.err_and_exit("Invalid domain or sub_domain or type in config file.")
def validate(self): if not self.accessId or not self.accessKey: DDNSUtils.err_and_exit( "Invalid access_id or access_key in config file.") for rec in self.localDomainRecordList: if not rec.domain or not rec.subDomain or not rec.type: DDNSUtils.err_and_exit( "Invalid domain or sub_domain or type in config file.")
def main(method, *args): """ Main routine """ config = DDNSConfig() record_manager = DDNSDomainRecordManager(config) # get current public ip for this server def switch(m): switcher = { "net": lambda: DDNSUtils.get_current_public_ip(), "static": lambda: args[0], } return switcher.get(m, lambda: "net|static 10.0.0.1") func = switch(method) current_public_ip = func() if not current_public_ip: DDNSUtils.err_and_exit("Failed to get current public IP") for local_record in record_manager.local_record_list: dns_resolved_ip = DDNSUtils.get_dns_resolved_ip(local_record.subdomain, local_record.domainname) if current_public_ip == dns_resolved_ip: DDNSUtils.info("Skipped as no changes for DomainRecord" \ "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record)) continue # If current public IP doesn't equal to current DNS resolved ip, only in three cases: # 1. The new synced IP for remote record in Aliyun doesn't take effect yet # 2. remote record's IP in Aliyun server has changed # 3. current public IP is changed remote_record = record_manager.fetch_remote_record(local_record) if not remote_record: DDNSUtils.err("Failed finding remote DomainRecord" \ "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record)) continue if current_public_ip == remote_record.value: DDNSUtils.info("Skipped as we already updated DomainRecord" \ "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record)) continue # if we can fetch remote record and record's value doesn't equal to public IP sync_result = record_manager.update(remote_record, current_public_ip) if not sync_result: DDNSUtils.err("Failed updating DomainRecord" \ "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record)) else: DDNSUtils.info("Successfully updated DomainRecord" \ "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record))
def perform_ddns(self): """ Perform the ddns process when everything is ready """ current_public_ip = DDNSUtils.get_current_public_ip() if not current_public_ip: DDNSUtils.err_and_exit("Failed to get local public IP") DDNSUtils.info( "Local public ip address read: [{0}]".format(current_public_ip)) for record_to_update in self.configuration.recordsToUpdate: dns_resolved_ip = record_to_update.get_dns_resolved_ip() if current_public_ip == dns_resolved_ip: DDNSUtils.info( "Skipped as no changes for DomainRecord: [{rec.subDomainName}.{rec.domainName}]" .format(rec=record_to_update)) continue # If current public IP doesn't equal to current DNS resolved ip, only in three cases: # 1. The new synchronized IP for remote record in api provider doesn't take effect yet # 2. remote record's IP in Aliyun server has changed # 3. current public IP is changed dns_record = self.get_dns_record(record_to_update) if not dns_record: DDNSUtils.err( "Failed to get dns resolution record for [{rec.subDomainName}.{rec.domainName}]" .format(rec=record_to_update)) continue if current_public_ip == dns_record.value: DDNSUtils.info( "Skipped: dns record already updated: [{rec.subDomainName}.{rec.domainName}]" .format(rec=record_to_update)) continue dns_record.value = current_public_ip result = self.update_dns_record(dns_record, current_public_ip) if not result: DDNSUtils.err( "Failed to update dns record: [{rec.subDomainName}.{rec.domainName}]" .format(rec=record_to_update)) else: DDNSUtils.info( "Successfully update dns record: [{rec.subDomainName}.{rec.domainName}]" .format(rec=record_to_update))
def main(): """ Main routine """ config = DDNSConfig() record_manager = DDNSDomainRecordManager(config) # get current public ip for this server current_public_ip = DDNSUtils.get_current_public_ip() if not current_public_ip: DDNSUtils.err_and_exit("Failed to get current public IP") for local_record in record_manager.local_record_list: dns_resolved_ip = DDNSUtils.get_dns_resolved_ip(local_record.subdomain, local_record.domainname) if current_public_ip == dns_resolved_ip: DDNSUtils.info("Skipped as no changes for DomainRecord" \ "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record)) continue # If current public IP doesn't equal to current DNS resolved ip, only in three cases: # 1. The new synced IP for remote record in Aliyun doesn't take effect yet # 2. remote record's IP in Aliyun server has changed # 3. current public IP is changed remote_record = record_manager.fetch_remote_record(local_record) if not remote_record: DDNSUtils.err("Failed finding remote DomainRecord" \ "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record)) continue if current_public_ip == remote_record.value: DDNSUtils.info("Skipped as we already updated DomainRecord" \ "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record)) continue # if we can fetch remote record and record's value doesn't equal to public IP sync_result = record_manager.update(remote_record, current_public_ip) if not sync_result: DDNSUtils.err("Failed updating DomainRecord" \ "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record)) else: DDNSUtils.info("Successfully updated DomainRecord" \ "[{rec.subdomain}.{rec.domainname}]".format(rec=local_record))
def get_feature_public_ip_from_nic_options(self): """ Get options about the getting ip from nic. """ section_name = "feature_public_ip_from_nic" try: enable = self.parser.getboolean(section_name, "enable") except ValueError as ex: DDNSUtils.err_and_exit( "Invalid 'enable' value in feature public_ip_from_nic config: {0}" .format(ex)) except ConfigParser.NoOptionError as ex: enable = False self.pifn_enable = enable if enable: try: self.pifn_interface = self.parser.get(section_name, "interface") except ConfigParser.NoOptionError as ex: DDNSUtils.err_and_exit("No interface specified") if self.pifn_interface == "": DDNSUtils.err_and_exit("Empty interface")
def from_config_file(cls, configFilePath): """ Construct a Config object from a given config file Args: configFilePath: path to the given config file Returns: Instance of Config """ parser = ConfigParser() if not parser.read(configFilePath): DDNSUtils.err_and_exit("Failed to read config file.") try: access_key_id = parser.get("ApiProvider", "access_key_id") access_key_secret = parser.get("ApiProvider", "access_key_secret") if not access_key_id or not access_key_secret: DDNSUtils.err_and_exit("Invalid access_id or access_key in config file.") apiProviderInfo = ApiProviderInfo(access_key_id, access_key_secret) DDNSUtils.info("Read Access Key Id: [{0}]".format(access_key_id)) DDNSUtils.info("Read Access Key Secret: [{0}]".format(access_key_secret)) recordsSections = [s for s in parser.sections() if s.startswith("DomainNameToUpdate") ] records = [] for record in recordsSections: domain = parser.get(record,'domain') type = parser.get(record,'type') subDomains = parser.get(record,'sub_domain').split(',') if not domain or not type or not subDomains: DDNSUtils.err_and_exit("Invalid domian record.") DDNSUtils.info("Read Domain: [{0}]".format(domain)) DDNSUtils.info("Read Sub Domains: [{0}]".format(subDomains)) DDNSUtils.info("Read Type: [{0}]".format(type)) for subDomain in subDomains: record = DomainSection(domain, subDomain.strip(), type) records.append(record) config = cls(apiProviderInfo, records) return config except ValueError as ex: DDNSUtils.err_and_exit("Invalid debug in config: {0}".format(ex)) except NoSectionError as ex: DDNSUtils.err_and_exit("Invalid config: {0}".format(ex)) except NoOptionError as ex: DDNSUtils.err_and_exit("Invalid config: {0}".format(ex))
from utils import DDNSUtils from config import DDNSConfig CONF_FILE = "/etc/ddns.conf" if __name__ == "__main__": config = DDNSConfig(CONF_FILE) config.validate() utils = DDNSUtils(config.debug) helper = DDNSHelper(config) # get current public ip currentPublicIP = utils.getCurrentPublicIP() if not currentPublicIP: DDNSUtils.err_and_exit("Failed to get current public ip") for localRecord in config.localDomainRecordList: # if we don't have domain record's id in config file, then we never sync to server before if not localRecord.id or not localRecord.value: result = helper.syncFirstTime(localRecord, currentPublicIP) if result is False: DDNSUtils.err_and_exit( "Failed doing the first time sync for record:{0}".format( localRecord.alias)) continue DDNSUtils.info("Successfully sync done for record:{0}".format( localRecord.alias)) continue
from utils import DDNSUtils from config import DDNSConfig CONF_FILE = "/etc/ddns.conf" if __name__ == "__main__": config = DDNSConfig(CONF_FILE) config.validate() utils = DDNSUtils(config.debug) helper = DDNSHelper(config) # get current public ip currentPublicIP = utils.getCurrentPublicIP() if not currentPublicIP: DDNSUtils.err_and_exit("Failed to get current public ip") for localRecord in config.localDomainRecordList: # if we don't have domain record's id in config file, then we never sync to server before if not localRecord.id or not localRecord.value: result = helper.syncFirstTime(localRecord,currentPublicIP) if result is False: DDNSUtils.err_and_exit("Failed doing the first time sync for record:{0}".format(localRecord.alias)) continue DDNSUtils.info("Successfully sync done for record:{0}".format(localRecord.alias)) continue # if current public ip is not the same as the one in server if currentPublicIP != localRecord.value: if config.debug:
"--access-key-secret", '-k', help='The access key secret assigned by ddns api provider.') argParser.add_argument( "--config", '-c', help= 'The configuration file to refer to for ddns process. If this option is set, all other options will be ignored.' ) args = argParser.parse_args() if args.config: CONFIG_FILE_PATH = args.config if not os.path.exists(CONFIG_FILE_PATH): DDNSUtils.err_and_exit('File not found: {0}'.format(CONFIG_FILE_PATH)) DDNSUtils.info( "Loading configuration from file: {0}".format(CONFIG_FILE_PATH)) config = Config.from_config_file(CONFIG_FILE_PATH) coordinator = DDNSCoordinator(config) coordinator.perform_ddns() pass elif not args.domains or not args.access_key_id or not args.access_key_secret: argParser.print_help() else: DDNSUtils.info("Loading configuration from arguments.") config = Config.from_cli_options(args.domains, args.access_key_id, args.access_key_secret, args.type) coordinator = DDNSCoordinator(config) coordinator.perform_ddns()