def render(self, session, logger, hostname, buildstatus, **arguments): dbhost = hostname_to_host(session, hostname) dbstatus = HostLifecycle.get_unique(session, buildstatus, compel=True) changed = dbhost.status.transition(dbhost, dbstatus) if not changed or not dbhost.archetype.is_compileable: return session.add(dbhost) session.flush() plenary = PlenaryHost(dbhost, logger=logger) # Force a host lock as pan might overwrite the profile... key = CompileKey(domain=dbhost.branch.name, profile=dbhost.fqdn, logger=logger) try: lock_queue.acquire(key) plenary.write(locked=True) td = TemplateDomain(dbhost.branch, dbhost.sandbox_author, logger=logger) td.compile(session, only=[dbhost.fqdn], locked=True) except IncompleteError: raise ArgumentError("Run aq make for host %s first." % dbhost.fqdn) except: plenary.restore_stash() raise finally: lock_queue.release(key)
def compile(self, session, logger, dbhost): """ compile plenary templates """ plenary = PlenaryHost(dbhost, logger=logger) # Force a host lock as pan might overwrite the profile... key = CompileKey(domain=dbhost.branch.name, profile=dbhost.fqdn, logger=logger) try: lock_queue.acquire(key) plenary.write(locked=True) td = TemplateDomain(dbhost.branch, dbhost.sandbox_author, logger=logger) td.compile(session, only=[dbhost.fqdn], locked=True) except IncompleteError: raise ArgumentError("Run aq make for host %s first." % dbhost.fqdn) except: plenary.restore_stash() raise finally: lock_queue.release(key)
def render( self, session, logger, machine, chassis, switch, interface, fqdn, ip, label, keep_dns, network_environment, **kwargs ): if machine: hwtype = "machine" hwname = machine elif chassis: hwtype = "chassis" hwname = chassis elif switch: hwtype = "switch" hwname = switch dbhw_ent = HardwareEntity.get_unique(session, hwname, hardware_type=hwtype, compel=True) dbinterface = Interface.get_unique(session, hardware_entity=dbhw_ent, name=interface, compel=True) dbnet_env = NetworkEnvironment.get_unique_or_default(session, network_environment) oldinfo = DSDBRunner.snapshot_hw(dbhw_ent) if fqdn: dbdns_rec = ARecord.get_unique(session, fqdn=fqdn, dns_environment=dbnet_env.dns_environment, compel=True) ip = dbdns_rec.ip addr = None if ip: addr = first_of(dbinterface.assignments, lambda x: x.ip == ip) if not addr: raise ArgumentError("{0} does not have IP address {1} assigned to " "it.".format(dbinterface, ip)) elif label is not None: addr = first_of(dbinterface.assignments, lambda x: x.label == label) if not addr: raise ArgumentError("{0} does not have an address with label " "{1}.".format(dbinterface, label)) if not addr: raise ArgumentError("Please specify the address to be removed " "using either --ip, --label, or --fqdn.") dbnetwork = addr.network ip = addr.ip if dbnetwork.network_environment != dbnet_env: raise ArgumentError( "The specified address lives in {0:l}, not in " "{1:l}. Use the --network_environment option " "to select the correct environment.".format(dbnetwork.network_environment, dbnet_env) ) # Forbid removing the primary name if ip == dbhw_ent.primary_ip: raise ArgumentError("The primary IP address of a hardware entity " "cannot be removed.") dbinterface.assignments.remove(addr) # Check if the address was assigned to multiple interfaces, and remove # the DNS entries if this was the last use q = session.query(AddressAssignment) q = q.filter_by(network=dbnetwork) q = q.filter_by(ip=ip) other_uses = q.all() if not other_uses and not keep_dns: q = session.query(ARecord) q = q.filter_by(network=dbnetwork) q = q.filter_by(ip=ip) q = q.join(ARecord.fqdn) q = q.filter_by(dns_environment=dbnet_env.dns_environment) map(delete_dns_record, q.all()) session.flush() dbhost = getattr(dbhw_ent, "host", None) if dbhost: plenary_info = PlenaryHost(dbhost, logger=logger) key = plenary_info.get_write_key() try: lock_queue.acquire(key) try: plenary_info.write(locked=True) except IncompleteError: # FIXME: if this command is used after "add host" but before # "make", then writing out the template will fail due to # required services not being assigned. Ignore this error # for now. plenary_info.restore_stash() dsdb_runner = DSDBRunner(logger=logger) dsdb_runner.update_host(dbhw_ent, oldinfo) if not other_uses and keep_dns: q = session.query(ARecord) q = q.filter_by(network=dbnetwork) q = q.filter_by(ip=ip) dbdns_rec = q.first() dsdb_runner.add_host_details(dbdns_rec.fqdn, ip) dsdb_runner.commit_or_rollback("Could not add host to DSDB") except: plenary_info.restore_stash() raise finally: lock_queue.release(key) else: dsdb_runner = DSDBRunner(logger=logger) dsdb_runner.update_host(dbhw_ent, oldinfo) dsdb_runner.commit_or_rollback("Could not add host to DSDB") return
def render(self, session, logger, machine, chassis, switch, interface, fqdn, ip, label, keep_dns, network_environment, **kwargs): if machine: hwtype = 'machine' hwname = machine elif chassis: hwtype = 'chassis' hwname = chassis elif switch: hwtype = 'switch' hwname = switch dbhw_ent = HardwareEntity.get_unique(session, hwname, hardware_type=hwtype, compel=True) dbinterface = Interface.get_unique(session, hardware_entity=dbhw_ent, name=interface, compel=True) dbnet_env = NetworkEnvironment.get_unique_or_default( session, network_environment) oldinfo = DSDBRunner.snapshot_hw(dbhw_ent) if fqdn: dbdns_rec = ARecord.get_unique( session, fqdn=fqdn, dns_environment=dbnet_env.dns_environment, compel=True) ip = dbdns_rec.ip addr = None if ip: addr = first_of(dbinterface.assignments, lambda x: x.ip == ip) if not addr: raise ArgumentError( "{0} does not have IP address {1} assigned to " "it.".format(dbinterface, ip)) elif label is not None: addr = first_of(dbinterface.assignments, lambda x: x.label == label) if not addr: raise ArgumentError("{0} does not have an address with label " "{1}.".format(dbinterface, label)) if not addr: raise ArgumentError("Please specify the address to be removed " "using either --ip, --label, or --fqdn.") dbnetwork = addr.network ip = addr.ip if dbnetwork.network_environment != dbnet_env: raise ArgumentError("The specified address lives in {0:l}, not in " "{1:l}. Use the --network_environment option " "to select the correct environment.".format( dbnetwork.network_environment, dbnet_env)) # Forbid removing the primary name if ip == dbhw_ent.primary_ip: raise ArgumentError("The primary IP address of a hardware entity " "cannot be removed.") dbinterface.assignments.remove(addr) # Check if the address was assigned to multiple interfaces, and remove # the DNS entries if this was the last use q = session.query(AddressAssignment) q = q.filter_by(network=dbnetwork) q = q.filter_by(ip=ip) other_uses = q.all() if not other_uses and not keep_dns: q = session.query(ARecord) q = q.filter_by(network=dbnetwork) q = q.filter_by(ip=ip) q = q.join(ARecord.fqdn) q = q.filter_by(dns_environment=dbnet_env.dns_environment) map(delete_dns_record, q.all()) session.flush() dbhost = getattr(dbhw_ent, "host", None) if dbhost: plenary_info = PlenaryHost(dbhost, logger=logger) key = plenary_info.get_write_key() try: lock_queue.acquire(key) try: plenary_info.write(locked=True) except IncompleteError: # FIXME: if this command is used after "add host" but before # "make", then writing out the template will fail due to # required services not being assigned. Ignore this error # for now. plenary_info.restore_stash() dsdb_runner = DSDBRunner(logger=logger) dsdb_runner.update_host(dbhw_ent, oldinfo) if not other_uses and keep_dns: q = session.query(ARecord) q = q.filter_by(network=dbnetwork) q = q.filter_by(ip=ip) dbdns_rec = q.first() dsdb_runner.add_host_details(dbdns_rec.fqdn, ip) dsdb_runner.commit_or_rollback("Could not add host to DSDB") except: plenary_info.restore_stash() raise finally: lock_queue.release(key) else: dsdb_runner = DSDBRunner(logger=logger) dsdb_runner.update_host(dbhw_ent, oldinfo) dsdb_runner.commit_or_rollback("Could not add host to DSDB") return
def render(self, session, logger, hostname, domain, sandbox, force, **arguments): (dbbranch, dbauthor) = get_branch_and_author(session, logger, domain=domain, sandbox=sandbox, compel=True) if hasattr(dbbranch, "allow_manage") and not dbbranch.allow_manage: raise ArgumentError("Managing hosts to {0:l} is not allowed." .format(dbbranch)) dbhost = hostname_to_host(session, hostname) dbsource = dbhost.branch dbsource_author = dbhost.sandbox_author old_branch = dbhost.branch.name if dbhost.cluster: raise ArgumentError("Cluster nodes must be managed at the " "cluster level; this host is a member of " "{0}.".format(dbhost.cluster)) if not force: validate_branch_commits(dbsource, dbsource_author, dbbranch, dbauthor, logger, self.config) dbhost.branch = dbbranch dbhost.sandbox_author = dbauthor session.add(dbhost) session.flush() plenary_host = PlenaryHost(dbhost, logger=logger) # We're crossing domains, need to lock everything. # XXX: There's a directory per domain. Do we need subdirectories # for different authors for a sandbox? key = CompileKey(logger=logger) try: lock_queue.acquire(key) plenary_host.stash() plenary_host.cleanup(old_branch, locked=True) # Now we recreate the plenary to ensure that the domain is ready # to compile, however (esp. if there was no existing template), we # have to be aware that there might not be enough information yet # with which we can create a template try: plenary_host.write(locked=True) except IncompleteError: # This template cannot be written, we leave it alone # It would be nice to flag the state in the the host? pass except: # This will not restore the cleaned up files. That's OK. # They will be recreated as needed. plenary_host.restore_stash() raise finally: lock_queue.release(key) return
def render(self, session, logger, machine, chassis, switch, fqdn, interface, label, network_environment, map_to_primary, **kwargs): if machine: hwtype = 'machine' hwname = machine elif chassis: hwtype = 'chassis' hwname = chassis elif switch: hwtype = 'switch' hwname = switch dbnet_env = NetworkEnvironment.get_unique_or_default( session, network_environment) dbhw_ent = HardwareEntity.get_unique(session, hwname, hardware_type=hwtype, compel=True) dbinterface = Interface.get_unique(session, hardware_entity=dbhw_ent, name=interface, compel=True) oldinfo = DSDBRunner.snapshot_hw(dbhw_ent) audit_results = [] ip = generate_ip(session, logger, dbinterface, network_environment=dbnet_env, audit_results=audit_results, **kwargs) if dbinterface.interface_type == "loopback": # Switch loopback interfaces may use e.g. the network address as an # IP address relaxed = True else: relaxed = False if not fqdn: if not dbhw_ent.primary_name: raise ArgumentError("{0} has no primary name, can not " "auto-generate the DNS record. " "Please specify --fqdn.".format(dbhw_ent)) if label: name = "%s-%s-%s" % (dbhw_ent.primary_name.fqdn.name, interface, label) else: name = "%s-%s" % (dbhw_ent.primary_name.fqdn.name, interface) fqdn = "%s.%s" % (name, dbhw_ent.primary_name.fqdn.dns_domain) if label is None: label = "" elif label == "hostname": # When add_host sets up Zebra, it always uses the label 'hostname'. # Due to the primary IP being special, add_interface_address cannot # really emulate what add_host does, so tell the user where to look. raise ArgumentError("The 'hostname' label can only be managed " "by add_host/del_host.") # The label will be used as an nlist key if label: validate_basic("label", label) # TODO: add allow_multi=True dbdns_rec, newly_created = grab_address(session, fqdn, ip, dbnet_env, relaxed=relaxed) ip = dbdns_rec.ip dbnetwork = dbdns_rec.network delete_old_dsdb_entry = not newly_created and not dbdns_rec.assignments # Reverse PTR control. Auxiliary addresses should point to the primary # name by default, with some exceptions. if (map_to_primary is None and dbhw_ent.primary_name and dbinterface.interface_type != "management" and dbdns_rec.fqdn.dns_environment == dbhw_ent.primary_name.fqdn.dns_environment): map_to_primary = True if map_to_primary: if not dbhw_ent.primary_name: raise ArgumentError( "{0} does not have a primary name, cannot " "set the reverse DNS mapping.".format(dbhw_ent)) if (dbhw_ent.primary_name.fqdn.dns_environment != dbdns_rec.fqdn.dns_environment): raise ArgumentError("{0} lives in {1:l}, not {2:l}.".format( dbhw_ent, dbhw_ent.primary_name.fqdn.dns_environment, dbdns_rec.fqdn.dns_environment)) if dbinterface.interface_type == "management": raise ArgumentError("The reverse PTR for management addresses " "should not point to the primary name.") dbdns_rec.reverse_ptr = dbhw_ent.primary_name.fqdn # Check that the network ranges assigned to different interfaces # do not overlap even if the network environments are different, because # that would confuse routing on the host. E.g. if eth0 is an internal # and eth1 is an external interface, then using 192.168.1.10/24 on eth0 # and using 192.168.1.20/26 on eth1 won't work. for addr in dbhw_ent.all_addresses(): if addr.network != dbnetwork and \ addr.network.network.overlaps(dbnetwork.network): raise ArgumentError("{0} in {1:l} used on {2:l} overlaps " "requested {3:l} in " "{4:l}.".format( addr.network, addr.network.network_environment, addr.interface, dbnetwork, dbnetwork.network_environment)) assign_address(dbinterface, ip, dbnetwork, label=label) session.flush() dbhost = getattr(dbhw_ent, "host", None) if dbhost: plenary_info = PlenaryHost(dbhost, logger=logger) key = plenary_info.get_write_key() try: lock_queue.acquire(key) try: plenary_info.write(locked=True) except IncompleteError: # FIXME: if this command is used after "add host" but before # "make", then writing out the template will fail due to # required services not being assigned. Ignore this error # for now. plenary_info.restore_stash() dsdb_runner = DSDBRunner(logger=logger) if delete_old_dsdb_entry: dsdb_runner.delete_host_details(dbdns_rec.fqdn, ip) dsdb_runner.update_host(dbhw_ent, oldinfo) dsdb_runner.commit_or_rollback("Could not add host to DSDB") except: plenary_info.restore_stash() raise finally: lock_queue.release(key) else: dsdb_runner = DSDBRunner(logger=logger) if delete_old_dsdb_entry: dsdb_runner.delete_host_details(dbdns_rec.fqdn, ip) dsdb_runner.update_host(dbhw_ent, oldinfo) dsdb_runner.commit_or_rollback("Could not add host to DSDB") for name, value in audit_results: self.audit_result(session, name, value, **kwargs) return
def render(self, session, logger, machine, chassis, switch, fqdn, interface, label, network_environment, map_to_primary, **kwargs): if machine: hwtype = 'machine' hwname = machine elif chassis: hwtype = 'chassis' hwname = chassis elif switch: hwtype = 'switch' hwname = switch dbnet_env = NetworkEnvironment.get_unique_or_default(session, network_environment) dbhw_ent = HardwareEntity.get_unique(session, hwname, hardware_type=hwtype, compel=True) dbinterface = Interface.get_unique(session, hardware_entity=dbhw_ent, name=interface, compel=True) oldinfo = DSDBRunner.snapshot_hw(dbhw_ent) audit_results = [] ip = generate_ip(session, logger, dbinterface, network_environment=dbnet_env, audit_results=audit_results, **kwargs) if dbinterface.interface_type == "loopback": # Switch loopback interfaces may use e.g. the network address as an # IP address relaxed = True else: relaxed = False if not fqdn: if not dbhw_ent.primary_name: raise ArgumentError("{0} has no primary name, can not " "auto-generate the DNS record. " "Please specify --fqdn.".format(dbhw_ent)) if label: name = "%s-%s-%s" % (dbhw_ent.primary_name.fqdn.name, interface, label) else: name = "%s-%s" % (dbhw_ent.primary_name.fqdn.name, interface) fqdn = "%s.%s" % (name, dbhw_ent.primary_name.fqdn.dns_domain) if label is None: label = "" elif label == "hostname": # When add_host sets up Zebra, it always uses the label 'hostname'. # Due to the primary IP being special, add_interface_address cannot # really emulate what add_host does, so tell the user where to look. raise ArgumentError("The 'hostname' label can only be managed " "by add_host/del_host.") # The label will be used as an nlist key if label: validate_basic("label", label) # TODO: add allow_multi=True dbdns_rec, newly_created = grab_address(session, fqdn, ip, dbnet_env, relaxed=relaxed) ip = dbdns_rec.ip dbnetwork = dbdns_rec.network delete_old_dsdb_entry = not newly_created and not dbdns_rec.assignments # Reverse PTR control. Auxiliary addresses should point to the primary # name by default, with some exceptions. if (map_to_primary is None and dbhw_ent.primary_name and dbinterface.interface_type != "management" and dbdns_rec.fqdn.dns_environment == dbhw_ent.primary_name.fqdn.dns_environment): map_to_primary = True if map_to_primary: if not dbhw_ent.primary_name: raise ArgumentError("{0} does not have a primary name, cannot " "set the reverse DNS mapping." .format(dbhw_ent)) if (dbhw_ent.primary_name.fqdn.dns_environment != dbdns_rec.fqdn.dns_environment): raise ArgumentError("{0} lives in {1:l}, not {2:l}." .format(dbhw_ent, dbhw_ent.primary_name.fqdn.dns_environment, dbdns_rec.fqdn.dns_environment)) if dbinterface.interface_type == "management": raise ArgumentError("The reverse PTR for management addresses " "should not point to the primary name.") dbdns_rec.reverse_ptr = dbhw_ent.primary_name.fqdn # Check that the network ranges assigned to different interfaces # do not overlap even if the network environments are different, because # that would confuse routing on the host. E.g. if eth0 is an internal # and eth1 is an external interface, then using 192.168.1.10/24 on eth0 # and using 192.168.1.20/26 on eth1 won't work. for addr in dbhw_ent.all_addresses(): if addr.network != dbnetwork and \ addr.network.network.overlaps(dbnetwork.network): raise ArgumentError("{0} in {1:l} used on {2:l} overlaps " "requested {3:l} in " "{4:l}.".format(addr.network, addr.network.network_environment, addr.interface, dbnetwork, dbnetwork.network_environment)) assign_address(dbinterface, ip, dbnetwork, label=label) session.flush() dbhost = getattr(dbhw_ent, "host", None) if dbhost: plenary_info = PlenaryHost(dbhost, logger=logger) key = plenary_info.get_write_key() try: lock_queue.acquire(key) try: plenary_info.write(locked=True) except IncompleteError: # FIXME: if this command is used after "add host" but before # "make", then writing out the template will fail due to # required services not being assigned. Ignore this error # for now. plenary_info.restore_stash() dsdb_runner = DSDBRunner(logger=logger) if delete_old_dsdb_entry: dsdb_runner.delete_host_details(dbdns_rec.fqdn, ip) dsdb_runner.update_host(dbhw_ent, oldinfo) dsdb_runner.commit_or_rollback("Could not add host to DSDB") except: plenary_info.restore_stash() raise finally: lock_queue.release(key) else: dsdb_runner = DSDBRunner(logger=logger) if delete_old_dsdb_entry: dsdb_runner.delete_host_details(dbdns_rec.fqdn, ip) dsdb_runner.update_host(dbhw_ent, oldinfo) dsdb_runner.commit_or_rollback("Could not add host to DSDB") for name, value in audit_results: self.audit_result(session, name, value, **kwargs) return