def render(self, session, logger, switch, **arguments): dbswitch = Switch.get_unique(session, switch, compel=True) # Check and complain if the switch has any other addresses than its # primary address addrs = [] for addr in dbswitch.all_addresses(): if addr.ip == dbswitch.primary_ip: continue addrs.append(str(addr.ip)) if addrs: raise ArgumentError("{0} still provides the following addresses, " "delete them first: {1}.".format (dbswitch, ", ".join(addrs))) dbdns_rec = dbswitch.primary_name ip = dbswitch.primary_ip old_fqdn = str(dbswitch.primary_name.fqdn) old_comments = dbswitch.comments session.delete(dbswitch) if dbdns_rec: delete_dns_record(dbdns_rec) session.flush() # Any switch ports hanging off this switch should be deleted with # the cascade delete of the switch. switch_plenary = Plenary.get_plenary(dbswitch, logger=logger) # clusters connected to this switch plenaries = PlenaryCollection(logger=logger) for dbcluster in dbswitch.esx_clusters: plenaries.append(Plenary.get_plenary(dbcluster)) key = CompileKey.merge([switch_plenary.get_remove_key(), plenaries.get_write_key()]) try: lock_queue.acquire(key) switch_plenary.stash() plenaries.write(locked=True) switch_plenary.remove(locked=True) if ip: dsdb_runner = DSDBRunner(logger=logger) # FIXME: restore interface name/MAC on rollback dsdb_runner.delete_host_details(old_fqdn, ip, comments=old_comments) dsdb_runner.commit_or_rollback("Could not remove switch from DSDB") return except: plenaries.restore_stash() switch_plenary.restore_stash() raise finally: lock_queue.release(key)
def del_dynamic_stubs(self, session, logger, dbstubs): dsdb_runner = DSDBRunner(logger=logger) for stub in dbstubs: dsdb_runner.delete_host_details(str(stub.fqdn), stub.ip) delete_dns_record(stub) session.flush() # This may take some time if the range is big, so be verbose dsdb_runner.commit_or_rollback(verbose=True)
def del_dynamic_stubs(self, session, logger, dbstubs): dsdb_runner = DSDBRunner(logger=logger) for stub in dbstubs: dsdb_runner.delete_host_details(str(stub.fqdn), stub.ip) delete_dns_record(stub) session.flush() # This may take some time if the range is big, so be verbose dsdb_runner.commit_or_rollback(verbose=True)
def render(self, session, logger, network_device, **arguments): dbnetdev = NetworkDevice.get_unique(session, network_device, compel=True) # Check and complain if the network device has any other addresses than its # primary address addrs = [] for addr in dbnetdev.all_addresses(): if addr.ip == dbnetdev.primary_ip: continue addrs.append(str(addr.ip)) if addrs: raise ArgumentError("{0} still provides the following addresses, " "delete them first: {1}.".format (dbnetdev, ", ".join(addrs))) dbdns_rec = dbnetdev.primary_name ip = dbnetdev.primary_ip old_fqdn = str(dbnetdev.primary_name.fqdn) old_comments = dbnetdev.comments session.delete(dbnetdev) if dbdns_rec: delete_dns_record(dbdns_rec) session.flush() # Any network device ports hanging off this network device should be deleted with # the cascade delete of the network device. netdev_plenary = Plenary.get_plenary(dbnetdev, logger=logger) # clusters connected to this network device plenaries = PlenaryCollection(logger=logger) for dbcluster in dbnetdev.esx_clusters: plenaries.append(Plenary.get_plenary(dbcluster)) with CompileKey.merge([netdev_plenary.get_key(), plenaries.get_key()]): netdev_plenary.stash() try: plenaries.write(locked=True) netdev_plenary.remove(locked=True) if ip: dsdb_runner = DSDBRunner(logger=logger) # FIXME: restore interface name/MAC on rollback dsdb_runner.delete_host_details(old_fqdn, ip, comments=old_comments) dsdb_runner.commit_or_rollback("Could not remove network device " "from DSDB") except: plenaries.restore_stash() netdev_plenary.restore_stash() raise return
def refresh_windows_hosts(self, session, logger, containers): conn = sqlite3.connect(self.config.get("broker", "windows_host_info")) # Enable dictionary-style access to the rows. conn.row_factory = sqlite3.Row windows_hosts = {} interfaces = {} cur = conn.cursor() # There are more fields in the dataset like machine and # aqhostname that might be useful for error messages but these # are sufficient. cur.execute("select ether, windowshostname from machines") for row in cur: host = row["windowshostname"] if host: host = host.strip().lower() else: continue mac = row["ether"] if mac: mac = mac.strip().lower() windows_hosts[host] = mac interfaces[mac] = host success = [] failed = [] q = session.query(Host) q = q.filter_by(comments='Created by refresh_windows_host') for dbhost in q.all(): dbmachine = dbhost.hardware_entity mac_addresses = [iface.mac for iface in dbmachine.interfaces] if dbhost.fqdn in windows_hosts and \ windows_hosts[dbhost.fqdn] in mac_addresses: # All is well continue try: check_no_provided_service(dbhost) except ArgumentError, err: msg = "Skipping removal of host %s due to: %s" % \ (dbhost.fqdn, err) failed.append(msg) logger.info(msg) continue success.append("Removed host entry for %s (%s)" % (dbmachine.label, dbmachine.fqdn)) if dbmachine.vm_container: containers.add(dbmachine.vm_container) logger.info("Deleting {0:l} (machine {1.label})" .format(dbhost, dbmachine)) session.delete(dbhost) dbdns_rec = dbmachine.primary_name dbmachine.primary_name = None delete_dns_record(dbdns_rec)
def render(self, session, logger, name, hostname, cluster, resourcegroup, keep_dns, **arguments): validate_basic("name", name) if name == "hostname": raise ArgumentError("The primary address of the host cannot " "be deleted.") holder = get_resource_holder(session, hostname, cluster, resourcegroup, compel=False) dbsrv = ServiceAddress.get_unique(session, name=name, holder=holder, compel=True) if isinstance(holder.holder_object, Host): oldinfo = DSDBRunner.snapshot_hw(holder.holder_object.machine) else: oldinfo = None dbdns_rec = dbsrv.dns_record for addr in dbsrv.assignments: addr.interface.assignments.remove(addr) session.expire(dbsrv, ['assignments']) session.flush() # 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=dbdns_rec.network) q = q.filter_by(ip=dbdns_rec.ip) other_uses = q.all() del_resource(session, logger, dbsrv, dsdb_callback=del_srv_dsdb_callback, oldinfo=oldinfo, keep_dns=other_uses or keep_dns) if not other_uses and not keep_dns: delete_dns_record(dbdns_rec) return
def render(self, session, logger, auxiliary, **arguments): dbmachine = None with DeleteKey("system", logger=logger): # Check dependencies, translate into user-friendly message dbauxiliary = ARecord.get_unique(session, fqdn=auxiliary, compel=True) is_aux = True if not dbauxiliary.assignments or len(dbauxiliary.assignments) > 1: is_aux = False else: assignment = dbauxiliary.assignments[0] dbmachine = assignment.interface.hardware_entity if assignment.ip == dbmachine.primary_ip: is_aux = False if assignment.interface.interface_type == 'management': is_aux = False if not is_aux: raise ArgumentError( "{0:a} is not an auxiliary.".format(dbauxiliary)) # FIXME: Look for dependencies... oldinfo = DSDBRunner.snapshot_hw(dbmachine) session.delete(assignment) delete_dns_record(dbauxiliary) session.flush() session.expire(dbmachine) dsdb_runner = DSDBRunner(logger=logger) dsdb_runner.update_host(dbmachine, oldinfo) dsdb_runner.commit_or_rollback( "Could not remove host %s from DSDB" % auxiliary) # Past the point of no return here (DSDB has been updated)... # probably not much of an issue if writing the plenary failed. # Commit the session so that we can free the delete lock. session.commit() if dbmachine: plenary_info = PlenaryMachineInfo(dbmachine, logger=logger) # This may create a new lock, so we free first above. plenary_info.write() if dbmachine.host: # FIXME: Reconfigure pass return
def render(self, session, logger, auxiliary, **arguments): dbmachine = None with DeleteKey("system", logger=logger): # Check dependencies, translate into user-friendly message dbauxiliary = ARecord.get_unique(session, fqdn=auxiliary, compel=True) is_aux = True if not dbauxiliary.assignments or len(dbauxiliary.assignments) > 1: is_aux = False else: assignment = dbauxiliary.assignments[0] dbmachine = assignment.interface.hardware_entity if assignment.ip == dbmachine.primary_ip: is_aux = False if assignment.interface.interface_type == "management": is_aux = False if not is_aux: raise ArgumentError("{0:a} is not an auxiliary.".format(dbauxiliary)) # FIXME: Look for dependencies... oldinfo = DSDBRunner.snapshot_hw(dbmachine) session.delete(assignment) delete_dns_record(dbauxiliary) session.flush() session.expire(dbmachine) dsdb_runner = DSDBRunner(logger=logger) dsdb_runner.update_host(dbmachine, oldinfo) dsdb_runner.commit_or_rollback("Could not remove host %s from DSDB" % auxiliary) # Past the point of no return here (DSDB has been updated)... # probably not much of an issue if writing the plenary failed. # Commit the session so that we can free the delete lock. session.commit() if dbmachine: plenary_info = PlenaryMachineInfo(dbmachine, logger=logger) # This may create a new lock, so we free first above. plenary_info.write() if dbmachine.host: # FIXME: Reconfigure pass return
def render(self, session, logger, fqdn, dns_environment, **kwargs): dbdns_env = DnsEnvironment.get_unique_or_default(session, dns_environment) dbdns_rec = Alias.get_unique(session, fqdn=fqdn, dns_environment=dbdns_env, compel=True) domain = dbdns_rec.fqdn.dns_domain.name old_target_fqdn = str(dbdns_rec.target) old_comments = dbdns_rec.comments target_is_restricted = dbdns_rec.target.dns_domain.restricted delete_dns_record(dbdns_rec) session.flush() if dbdns_env.is_default and domain == "ms.com" and not target_is_restricted: dsdb_runner = DSDBRunner(logger=logger) dsdb_runner.del_alias(fqdn, old_target_fqdn, old_comments) dsdb_runner.commit_or_rollback("Could not delete alias from DSDB") return
def render(self, session, logger, name, hostname, cluster, resourcegroup, keep_dns, **arguments): validate_basic("name", name) if name == "hostname": raise ArgumentError("The primary address of the host cannot " "be deleted.") holder = get_resource_holder(session, hostname, cluster, resourcegroup, compel=False) dbsrv = ServiceAddress.get_unique(session, name=name, holder=holder, compel=True) if isinstance(holder.holder_object, Host): oldinfo = DSDBRunner.snapshot_hw(holder.holder_object.machine) else: oldinfo = None dbdns_rec = dbsrv.dns_record for addr in dbsrv.assignments: addr.interface.assignments.remove(addr) session.expire(dbsrv, ['assignments']) session.flush() # 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=dbdns_rec.network) q = q.filter_by(ip=dbdns_rec.ip) other_uses = q.all() del_resource(session, logger, dbsrv, dsdb_callback=del_srv_dsdb_callback, oldinfo=oldinfo, keep_dns=other_uses or keep_dns) if not other_uses and not keep_dns: delete_dns_record(dbdns_rec) return
def render(self, session, logger, chassis, clear_slots, **arguments): dbchassis = Chassis.get_unique(session, chassis, compel=True) # Check and complain if the chassis has any other addresses than its # primary address addrs = [] for addr in dbchassis.all_addresses(): if addr.ip == dbchassis.primary_ip: continue addrs.append(str(addr.ip)) if addrs: raise ArgumentError("{0} still provides the following addresses, " "delete them first: {1}.".format (dbchassis, ", ".join(addrs))) q = session.query(ChassisSlot) q = q.filter_by(chassis=dbchassis) q = q.filter(ChassisSlot.machine_id != None) machine_count = q.count() if machine_count > 0 and not clear_slots: raise ArgumentError("{0} is still in use by {1} machines. Use " "--clear_slots if you really want to delete " "it.".format(dbchassis, machine_count)) # Order matters here dbdns_rec = dbchassis.primary_name ip = dbchassis.primary_ip old_fqdn = str(dbchassis.primary_name.fqdn) old_comments = dbchassis.primary_name.comments session.delete(dbchassis) if dbdns_rec: delete_dns_record(dbdns_rec) session.flush() if ip: dsdb_runner = DSDBRunner(logger=logger) dsdb_runner.delete_host_details(old_fqdn, ip, comments=old_comments) dsdb_runner.commit_or_rollback("Could not remove chassis from DSDB") return
def render(self, session, logger, fqdn, dns_environment, **kwargs): dbdns_env = DnsEnvironment.get_unique_or_default( session, dns_environment) dbdns_rec = Alias.get_unique(session, fqdn=fqdn, dns_environment=dbdns_env, compel=True) domain = dbdns_rec.fqdn.dns_domain.name old_target_fqdn = str(dbdns_rec.target) old_comments = dbdns_rec.comments target_is_restricted = dbdns_rec.target.dns_domain.restricted delete_dns_record(dbdns_rec) session.flush() if dbdns_env.is_default and domain == "ms.com" and not target_is_restricted: dsdb_runner = DSDBRunner(logger=logger) dsdb_runner.del_alias(fqdn, old_target_fqdn, old_comments) dsdb_runner.commit_or_rollback("Could not delete alias from DSDB") return
def remove_prev(self, session, logger, prev, pending_removals): """Remove the interface 'prev' and its host and machine.""" # This should probably be re-factored to call code used elsewhere. # The below seems too simple to warrant that, though... logger.info( "Removing blind host '%s', machine '%s', " "and interface '%s'" % (prev.hardware_entity.fqdn, prev.hardware_entity.label, prev.name) ) host_plenary_info = Plenary.get_plenary(prev.hardware_entity.host, logger=logger) # FIXME: Should really do everything that del_host.py does, not # just remove the host plenary but adjust all the service # plenarys and dependency files. pending_removals.append(host_plenary_info) dbmachine = prev.hardware_entity machine_plenary_info = Plenary.get_plenary(dbmachine, logger=logger) pending_removals.append(machine_plenary_info) # This will cascade to prev & the host if dbmachine.primary_name: dbdns_rec = dbmachine.primary_name dbmachine.primary_name = None delete_dns_record(dbdns_rec) session.delete(dbmachine) session.flush()
def remove_prev(self, session, logger, prev, pending_removals): """Remove the interface 'prev' and its host and machine.""" # This should probably be re-factored to call code used elsewhere. # The below seems too simple to warrant that, though... logger.info( "Removing blind host '%s', machine '%s', " "and interface '%s'" % (prev.hardware_entity.fqdn, prev.hardware_entity.label, prev.name)) host_plenary_info = Plenary.get_plenary(prev.hardware_entity.host, logger=logger) # FIXME: Should really do everything that del_host.py does, not # just remove the host plenary but adjust all the service # plenarys and dependency files. pending_removals.append(host_plenary_info) dbmachine = prev.hardware_entity machine_plenary_info = Plenary.get_plenary(dbmachine, logger=logger) pending_removals.append(machine_plenary_info) # This will cascade to prev & the host if dbmachine.primary_name: dbdns_rec = dbmachine.primary_name dbmachine.primary_name = None delete_dns_record(dbdns_rec) session.delete(dbmachine) session.flush()
def render(self, session, logger, fqdn, ip, dns_environment, network_environment, **arguments): if network_environment: if not isinstance(network_environment, NetworkEnvironment): network_environment = NetworkEnvironment.get_unique_or_default(session, network_environment) if not dns_environment: dns_environment = network_environment.dns_environment dbdns_env = DnsEnvironment.get_unique(session, dns_environment, compel=True) with DeleteKey("system", logger=logger): # We can't use get_unique() here, since we always want to filter by # DNS environment, even if no FQDN was given q = session.query(ARecord) if ip: q = q.filter_by(ip=ip) q = q.join(ARecord.fqdn) q = q.options(contains_eager('fqdn')) q = q.filter_by(dns_environment=dbdns_env) if fqdn: (name, dbdns_domain) = parse_fqdn(session, fqdn) q = q.filter_by(name=name) q = q.filter_by(dns_domain=dbdns_domain) try: dbaddress = q.one() except NoResultFound: parts = [] if fqdn: parts.append(fqdn) if ip: parts.append("ip %s" % ip) raise NotFoundException("DNS Record %s not found." % ", ".join(parts)) except MultipleResultsFound: parts = [] if fqdn: parts.append(fqdn) if ip: parts.append("ip %s" % ip) raise NotFoundException("DNS Record %s is not unique." % ", ".join(parts)) if dbaddress.hardware_entity: raise ArgumentError("DNS Record {0:a} is the primary name of " "{1:l}, therefore it cannot be " "deleted.".format(dbaddress, dbaddress.hardware_entity)) if dbaddress.service_address: # TODO: print the holder object raise ArgumentError("DNS Record {0:a} is used as a service " "address, therefore it cannot be deleted." .format(dbaddress)) # Do not allow deleting the DNS record if the IP address is still in # use - except if there are other DNS records having the same # address if dbaddress.assignments: last_use = [] # FIXME: race condition here, we should use # SELECT ... FOR UPDATE for addr in dbaddress.assignments: if len(addr.dns_records) == 1: last_use.append(addr) if last_use: users = " ,".join([format(addr.interface, "l") for addr in last_use]) raise ArgumentError("IP address %s is still in use by %s." % (ip, users)) ip = dbaddress.ip old_fqdn = str(dbaddress.fqdn) old_comments = dbaddress.comments delete_dns_record(dbaddress) session.flush() if dbdns_env.is_default: dsdb_runner = DSDBRunner(logger=logger) dsdb_runner.delete_host_details(old_fqdn, ip, comments=old_comments) dsdb_runner.commit_or_rollback() return
def render(self, session, logger, hostname, **arguments): # removing the plenary host requires a compile lock, however # we want to avoid deadlock by the fact that we're messing # with two locks here, so we want to be careful. We grab the # plenaryhost early on (in order to get the filenames filled # in from the db info before we delete it from the db. We then # hold onto those references until we've completed the db # cleanup and if all of that is successful, then we delete the # plenary file (which doesn't require re-evaluating any stale # db information) after we've released the delhost lock. delplenary = False # Any service bindings that we need to clean up afterwards bindings = PlenaryCollection(logger=logger) resources = PlenaryCollection(logger=logger) with DeleteKey("system", logger=logger) as key: # Check dependencies, translate into user-friendly message dbhost = hostname_to_host(session, hostname) host_plenary = Plenary.get_plenary(dbhost, logger=logger) domain = dbhost.branch.name deps = get_host_dependencies(session, dbhost) if (len(deps) != 0): deptext = "\n".join([" %s" % d for d in deps]) raise ArgumentError("Cannot delete host %s due to the " "following dependencies:\n%s." % (hostname, deptext)) archetype = dbhost.archetype.name dbmachine = dbhost.machine oldinfo = DSDBRunner.snapshot_hw(dbmachine) ip = dbmachine.primary_ip fqdn = dbmachine.fqdn for si in dbhost.services_used: plenary = PlenaryServiceInstanceServer(si) bindings.append(plenary) logger.info("Before deleting host '%s', removing binding '%s'" % (fqdn, si.cfg_path)) del dbhost.services_used[:] if dbhost.resholder: for res in dbhost.resholder.resources: resources.append(Plenary.get_plenary(res)) # In case of Zebra, the IP may be configured on multiple interfaces for iface in dbmachine.interfaces: if ip in iface.addresses: iface.addresses.remove(ip) if dbhost.cluster: dbcluster = dbhost.cluster dbcluster.hosts.remove(dbhost) set_committed_value(dbhost, '_cluster', None) dbcluster.validate() dbdns_rec = dbmachine.primary_name dbmachine.primary_name = None dbmachine.host = None session.delete(dbhost) delete_dns_record(dbdns_rec) session.flush() delplenary = True if dbmachine.vm_container: bindings.append(Plenary.get_plenary(dbmachine.vm_container)) if archetype != 'aurora' and ip is not None: dsdb_runner = DSDBRunner(logger=logger) dsdb_runner.update_host(dbmachine, oldinfo) dsdb_runner.commit_or_rollback("Could not remove host %s from " "DSDB" % hostname) if archetype == 'aurora': logger.client_info("WARNING: removing host %s from AQDB and " "*not* changing DSDB." % hostname) # Past the point of no return... commit the transaction so # that we can free the delete lock. session.commit() # Only if we got here with no exceptions do we clean the template # Trying to clean up after any errors here is really difficult # since the changes to dsdb have already been made. if (delplenary): key = host_plenary.get_remove_key() with CompileKey.merge([key, bindings.get_write_key(), resources.get_remove_key()]) as key: host_plenary.cleanup(domain, locked=True) # And we also want to remove the profile itself profiles = self.config.get("broker", "profilesdir") # Only one of these should exist, but it doesn't hurt # to try to clean up both. xmlfile = os.path.join(profiles, fqdn + ".xml") remove_file(xmlfile, logger=logger) xmlgzfile = xmlfile + ".gz" remove_file(xmlgzfile, logger=logger) # And the cached template created by ant remove_file(os.path.join(self.config.get("broker", "quattordir"), "objects", fqdn + TEMPLATE_EXTENSION), logger=logger) bindings.write(locked=True) resources.remove(locked=True) build_index(self.config, session, profiles, logger=logger) return
def refresh_windows_hosts(self, session, logger, containers): conn = sqlite3.connect(self.config.get("broker", "windows_host_info")) # Enable dictionary-style access to the rows. conn.row_factory = sqlite3.Row windows_hosts = {} interfaces = {} cur = conn.cursor() # There are more fields in the dataset like machine and # aqhostname that might be useful for error messages but these # are sufficient. cur.execute("select ether, windowshostname from machines") for row in cur: host = row["windowshostname"] if host: host = host.strip().lower() else: continue mac = row["ether"] if mac: mac = mac.strip().lower() windows_hosts[host] = mac interfaces[mac] = host success = [] failed = [] q = session.query(Host) q = q.filter_by(comments='Created by refresh_windows_host') for dbhost in q.all(): mac_addresses = [iface.mac for iface in dbhost.machine.interfaces] if dbhost.fqdn in windows_hosts and \ windows_hosts[dbhost.fqdn] in mac_addresses: # All is well continue deps = get_host_dependencies(session, dbhost) if deps: msg = "Skipping removal of host %s with dependencies: %s" % \ (dbhost.fqdn, ", ".join(deps)) failed.append(msg) logger.info(msg) continue dbmachine = dbhost.machine success.append("Removed host entry for %s (%s)" % (dbmachine.label, dbmachine.fqdn)) if dbmachine.vm_container: containers.add(dbmachine.vm_container) session.delete(dbhost) dbdns_rec = dbmachine.primary_name dbmachine.primary_name = None delete_dns_record(dbdns_rec) session.flush() # The Host() creations below fail when autoflush is enabled. session.autoflush = False dbdomain = Domain.get_unique(session, self.config.get("archetype_windows", "host_domain"), compel=InternalError) dbarchetype = Archetype.get_unique(session, "windows", compel=InternalError) dbpersonality = Personality.get_unique(session, archetype=dbarchetype, name="generic", compel=InternalError) dbstatus = HostLifecycle.get_unique(session, "ready", compel=InternalError) dbos = OperatingSystem.get_unique(session, name="windows", version="generic", archetype=dbarchetype, compel=InternalError) for (host, mac) in windows_hosts.items(): try: (short, dbdns_domain) = parse_fqdn(session, host) except AquilonError, err: msg = "Skipping host %s: %s" % (host, err) failed.append(msg) logger.info(msg) continue existing = DnsRecord.get_unique(session, name=short, dns_domain=dbdns_domain) if existing: if not existing.hardware_entity: msg = "Skipping host %s: It is not a primary name." % host failed.append(msg) logger.info(msg) continue # If these are invalid there should have been a deletion # attempt above. if not existing.hardware_entity.interfaces: msg = "Skipping host %s: Host already exists but has " \ "no interface attached." % host failed.append(msg) logger.info(msg) elif existing.hardware_entity.interfaces[0].mac != mac: msg = "Skipping host %s: Host already exists but with " \ "MAC address %s and not %s." % \ (host, existing.hardware_entity.interfaces[0].mac, mac) failed.append(msg) logger.info(msg) continue dbinterface = session.query(Interface).filter_by(mac=mac).first() if not dbinterface: msg = "Skipping host %s: MAC address %s is not present in " \ "AQDB." % (host, mac) failed.append(msg) logger.info(msg) continue q = session.query(Machine) q = q.filter_by(id=dbinterface.hardware_entity.id) dbmachine = q.first() if not dbmachine: msg = "Skipping host %s: The AQDB interface with MAC address " \ "%s is tied to hardware %s instead of a virtual " \ "machine." % \ (host, mac, dbinterface.hardware_entity.label) failed.append(msg) logger.info(msg) continue if dbinterface.assignments: msg = "Skipping host %s: The AQDB interface with MAC address " \ "%s is already tied to %s." % \ (host, mac, dbinterface.assignments[0].fqdns[0]) failed.append(msg) logger.info(msg) continue if dbmachine.host: msg = "Skipping host %s: The AQDB interface with MAC address " \ "%s is already tied to %s." % \ (host, mac, dbmachine.fqdn) failed.append(msg) logger.info(msg) continue dbhost = Host(machine=dbmachine, branch=dbdomain, status=dbstatus, owner_grn=dbpersonality.owner_grn, personality=dbpersonality, operating_system=dbos, comments="Created by refresh_windows_host") session.add(dbhost) if self.config.has_option("archetype_windows", "default_grn_target"): dbhost.grns.append((dbhost, dbgrn, self.config.get("archetype_", "default_grn_target"))) dbfqdn = Fqdn.get_or_create(session, name=short, dns_domain=dbdns_domain, preclude=True) dbdns_rec = ReservedName(fqdn=dbfqdn) session.add(dbdns_rec) dbmachine.primary_name = dbdns_rec success.append("Added host entry for %s (%s)." % (dbmachine.label, dbdns_rec.fqdn)) if dbmachine.vm_container: containers.add(dbmachine.vm_container) session.flush()
def render(self, session, logger, hostname, **arguments): # Check dependencies, translate into user-friendly message dbhost = hostname_to_host(session, hostname) dbhost.lock_row() check_no_provided_service(dbhost) # Any service bindings that we need to clean up afterwards plenaries = PlenaryCollection(logger=logger) remove_plenaries = PlenaryCollection(logger=logger) remove_plenaries.append(Plenary.get_plenary(dbhost)) archetype = dbhost.archetype.name dbmachine = dbhost.hardware_entity oldinfo = DSDBRunner.snapshot_hw(dbmachine) ip = dbmachine.primary_ip for si in dbhost.services_used: plenaries.append(PlenaryServiceInstanceServer.get_plenary(si)) logger.info("Before deleting {0:l}, removing binding to {1:l}" .format(dbhost, si)) del dbhost.services_used[:] if dbhost.resholder: for res in dbhost.resholder.resources: remove_plenaries.append(Plenary.get_plenary(res)) # In case of Zebra, the IP may be configured on multiple interfaces for iface in dbmachine.interfaces: if ip in iface.addresses: iface.addresses.remove(ip) if dbhost.cluster: dbcluster = dbhost.cluster dbcluster.hosts.remove(dbhost) set_committed_value(dbhost, '_cluster', None) dbcluster.validate() plenaries.append(Plenary.get_plenary(dbcluster)) dbdns_rec = dbmachine.primary_name dbmachine.primary_name = None dbmachine.host = None session.delete(dbhost) delete_dns_record(dbdns_rec) session.flush() if dbmachine.vm_container: plenaries.append(Plenary.get_plenary(dbmachine.vm_container)) with CompileKey.merge([plenaries.get_key(), remove_plenaries.get_key()]): plenaries.stash() remove_plenaries.stash() try: plenaries.write(locked=True) remove_plenaries.remove(locked=True, remove_profile=True) if archetype != 'aurora' and ip is not None: dsdb_runner = DSDBRunner(logger=logger) dsdb_runner.update_host(dbmachine, oldinfo) dsdb_runner.commit_or_rollback("Could not remove host %s from " "DSDB" % hostname) if archetype == 'aurora': logger.client_info("WARNING: removing host %s from AQDB and " "*not* changing DSDB." % hostname) except: plenaries.restore_stash() remove_plenaries.restore_stash() raise trigger_notifications(self.config, logger, CLIENT_INFO) return
def render(self, session, logger, hostname, **arguments): # removing the plenary host requires a compile lock, however # we want to avoid deadlock by the fact that we're messing # with two locks here, so we want to be careful. We grab the # plenaryhost early on (in order to get the filenames filled # in from the db info before we delete it from the db. We then # hold onto those references until we've completed the db # cleanup and if all of that is successful, then we delete the # plenary file (which doesn't require re-evaluating any stale # db information) after we've released the delhost lock. delplenary = False # Any service bindings that we need to clean up afterwards bindings = PlenaryCollection(logger=logger) resources = PlenaryCollection(logger=logger) with DeleteKey("system", logger=logger) as key: # Check dependencies, translate into user-friendly message dbhost = hostname_to_host(session, hostname) host_plenary = Plenary.get_plenary(dbhost, logger=logger) domain = dbhost.branch.name deps = get_host_dependencies(session, dbhost) if (len(deps) != 0): deptext = "\n".join([" %s" % d for d in deps]) raise ArgumentError("Cannot delete host %s due to the " "following dependencies:\n%s." % (hostname, deptext)) archetype = dbhost.archetype.name dbmachine = dbhost.machine oldinfo = DSDBRunner.snapshot_hw(dbmachine) ip = dbmachine.primary_ip fqdn = dbmachine.fqdn for si in dbhost.services_used: plenary = PlenaryServiceInstanceServer(si) bindings.append(plenary) logger.info( "Before deleting host '%s', removing binding '%s'" % (fqdn, si.cfg_path)) del dbhost.services_used[:] if dbhost.resholder: for res in dbhost.resholder.resources: resources.append(Plenary.get_plenary(res)) # In case of Zebra, the IP may be configured on multiple interfaces for iface in dbmachine.interfaces: if ip in iface.addresses: iface.addresses.remove(ip) if dbhost.cluster: dbcluster = dbhost.cluster dbcluster.hosts.remove(dbhost) set_committed_value(dbhost, '_cluster', None) dbcluster.validate() dbdns_rec = dbmachine.primary_name dbmachine.primary_name = None dbmachine.host = None session.delete(dbhost) delete_dns_record(dbdns_rec) session.flush() delplenary = True if dbmachine.vm_container: bindings.append(Plenary.get_plenary(dbmachine.vm_container)) if archetype != 'aurora' and ip is not None: dsdb_runner = DSDBRunner(logger=logger) dsdb_runner.update_host(dbmachine, oldinfo) dsdb_runner.commit_or_rollback("Could not remove host %s from " "DSDB" % hostname) if archetype == 'aurora': logger.client_info("WARNING: removing host %s from AQDB and " "*not* changing DSDB." % hostname) # Past the point of no return... commit the transaction so # that we can free the delete lock. session.commit() # Only if we got here with no exceptions do we clean the template # Trying to clean up after any errors here is really difficult # since the changes to dsdb have already been made. if (delplenary): key = host_plenary.get_remove_key() with CompileKey.merge( [key, bindings.get_write_key(), resources.get_remove_key()]) as key: host_plenary.cleanup(domain, locked=True) # And we also want to remove the profile itself profiles = self.config.get("broker", "profilesdir") # Only one of these should exist, but it doesn't hurt # to try to clean up both. xmlfile = os.path.join(profiles, fqdn + ".xml") remove_file(xmlfile, logger=logger) xmlgzfile = xmlfile + ".gz" remove_file(xmlgzfile, logger=logger) # And the cached template created by ant remove_file(os.path.join( self.config.get("broker", "quattordir"), "objects", fqdn + TEMPLATE_EXTENSION), logger=logger) bindings.write(locked=True) resources.remove(locked=True) build_index(self.config, session, profiles, logger=logger) return