def update_primary_ip(session, dbhw_ent, ip): if not dbhw_ent.primary_name: raise ArgumentError( "{0} does not have a primary name.".format(dbhw_ent)) dbnetwork = get_net_id_from_ip(session, ip) check_ip_restrictions(dbnetwork, ip) # The primary address must be unique q = session.query(AddressAssignment) q = q.filter_by(network=dbnetwork) q = q.filter_by(ip=ip) addr = q.first() if addr: raise ArgumentError( "IP address {0} is already in use by {1:l}.".format( ip, addr.interface)) # Convert ReservedName to ARecord if needed if isinstance(dbhw_ent.primary_name, ReservedName): convert_reserved_to_arecord(session, dbhw_ent.primary_name, dbnetwork, ip) # When converting a ReservedName to an ARecord, we have to bind the # primary address to an interface. Try to pick one. dbinterface = first_of(dbhw_ent.interfaces, lambda x: x.bootable) if not dbinterface: dbinterface = first_of(dbhw_ent.interfaces, lambda x: x.interface_type != "management") if not dbinterface: # pragma: no cover raise AquilonError("Cannot update the primary IP address of {0:l} " "because it does not have any interfaces " "defined.".format(dbhw_ent)) assign_address(dbinterface, ip, dbnetwork) else: dns_rec = dbhw_ent.primary_name q = session.query(AddressAssignment) q = q.filter_by(network=dns_rec.network) q = q.filter_by(ip=dns_rec.ip) q = q.join(Interface) q = q.filter_by(hardware_entity=dbhw_ent) # In case of Zebra, the address may be assigned to multiple interfaces addrs = q.all() dns_rec.ip = ip dns_rec.network = dbnetwork for addr in addrs: addr.ip = ip addr.network = dbnetwork
def update_primary_ip(session, logger, dbhw_ent, ip): if not dbhw_ent.primary_name: raise ArgumentError("{0} does not have a primary name." .format(dbhw_ent)) dbnetwork = get_net_id_from_ip(session, ip) check_ip_restrictions(dbnetwork, ip) # The primary address must be unique q = session.query(AddressAssignment) q = q.filter_by(network=dbnetwork) q = q.filter_by(ip=ip) addr = q.first() if addr: raise ArgumentError("IP address {0} is already in use by {1:l}." .format(ip, addr.interface)) # Convert ReservedName to ARecord if needed if isinstance(dbhw_ent.primary_name, ReservedName): convert_reserved_to_arecord(session, dbhw_ent.primary_name, dbnetwork, ip) # When converting a ReservedName to an ARecord, we have to bind the # primary address to an interface. Try to pick one. dbinterface = first_of(dbhw_ent.interfaces, lambda x: x.bootable) if not dbinterface: dbinterface = first_of(dbhw_ent.interfaces, lambda x: x.interface_type != "management") if not dbinterface: # pragma: no cover raise AquilonError("Cannot update the primary IP address of {0:l} " "because it does not have any interfaces " "defined.".format(dbhw_ent)) assign_address(dbinterface, ip, dbnetwork, logger=logger) else: dns_rec = dbhw_ent.primary_name q = session.query(AddressAssignment) q = q.filter_by(network=dns_rec.network) q = q.filter_by(ip=dns_rec.ip) q = q.join(Interface) q = q.filter_by(hardware_entity=dbhw_ent) # In case of Zebra, the address may be assigned to multiple interfaces addrs = q.all() dns_rec.ip = ip dns_rec.network = dbnetwork for addr in addrs: addr.ip = ip addr.network = dbnetwork
continue if iface.name in data["interfaces"]: # No change to the interface, just do some administration iface_by_name[iface.name] = iface name_by_iface[iface] = iface.name else: # We don't have an interface with the same name. Check if a # discovered interface has our IP, and rename the existing interface # if that's the case. delete_iface = True if iface.assignments: ip = iface.assignments[0].ip if ip in ip_to_iface: new_name = ip_to_iface[ip]["name"] iface2 = first_of(dbswitch.interfaces, lambda i: i.name == new_name) if iface2 and iface2.assignments: # The target name already exists, it has other # addresses, we have no choice than delete and re-add # the addresses pass else: # If the target name already exists but has no # addresses, then we can delete it and rename the # current interface if iface2 and iface2 not in ifaces_to_delete: ifaces_to_delete.append(iface2) iface_by_name[new_name] = iface name_by_iface[iface] = new_name delete_iface = False
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, interface, machine, mac, model, vendor, boot, pg, autopg, comments, master, clear_master, default_route, rename_to, **arguments ): """This command expects to locate an interface based only on name and machine - all other fields, if specified, are meant as updates. If the machine has a host, dsdb may need to be updated. The boot flag can *only* be set to true. This is mostly technical, as at this point in the interface it is difficult to tell if the flag was unset or set to false. However, it also vastly simplifies the dsdb logic - we never have to worry about a user trying to remove the boot flag from a host in dsdb. """ audit_results = [] dbhw_ent = Machine.get_unique(session, machine, compel=True) dbinterface = Interface.get_unique(session, hardware_entity=dbhw_ent, name=interface, compel=True) oldinfo = DSDBRunner.snapshot_hw(dbhw_ent) if arguments.get("hostname", None): # Hack to set an intial interface for an aurora host... dbhost = dbhw_ent.host if dbhost.archetype.name == "aurora" and dbhw_ent.primary_ip and not dbinterface.addresses: assign_address(dbinterface, dbhw_ent.primary_ip, dbhw_ent.primary_name.network) # We may need extra IP verification (or an autoip option)... # This may also throw spurious errors if attempting to set the # port_group to a value it already has. if pg is not None and dbinterface.port_group != pg.lower().strip(): dbinterface.port_group = verify_port_group(dbinterface.hardware_entity, pg) elif autopg: dbinterface.port_group = choose_port_group(session, logger, dbinterface.hardware_entity) audit_results.append(("pg", dbinterface.port_group)) if master: if dbinterface.addresses: # FIXME: as a special case, if the only address is the # primary IP, then we could just move it to the master # interface. However this can be worked around by bonding # the interface before calling "add host", so don't bother # for now. raise ArgumentError("Can not enslave {0:l} because it has " "addresses.".format(dbinterface)) dbmaster = Interface.get_unique(session, hardware_entity=dbhw_ent, name=master, compel=True) if dbmaster in dbinterface.all_slaves(): raise ArgumentError( "Enslaving {0:l} would create a circle, " "which is not allowed.".format(dbinterface) ) dbinterface.master = dbmaster if clear_master: if not dbinterface.master: raise ArgumentError("{0} is not a slave.".format(dbinterface)) dbinterface.master = None if comments: dbinterface.comments = comments if boot: # Should we also transfer the primary IP to the new boot interface? # That could get tricky if the new interface already has an IP # address... for i in dbhw_ent.interfaces: if i == dbinterface: i.bootable = True i.default_route = True else: i.bootable = False i.default_route = False if default_route is not None: dbinterface.default_route = default_route if not first_of(dbhw_ent.interfaces, lambda x: x.default_route): logger.client_info("Warning: {0:l} has no default route, hope " "that's ok.".format(dbhw_ent)) # Set this mac address last so that you can update to a bootable # interface *before* adding a mac address. This is so the validation # that takes place in the interface class doesn't have to be worried # about the order of update to bootable=True and mac address if mac: q = session.query(Interface).filter_by(mac=mac) other = q.first() if other and other != dbinterface: raise ArgumentError("MAC address {0} is already in use by " "{1:l}.".format(mac, other)) dbinterface.mac = mac if model or vendor: if not dbinterface.model_allowed: raise ArgumentError("Model/vendor can not be set for a {0:lc}.".format(dbinterface)) dbmodel = Model.get_unique(session, name=model, vendor=vendor, machine_type="nic", compel=True) dbinterface.model = dbmodel if rename_to: rename_interface(session, dbinterface, rename_to) session.flush() session.refresh(dbhw_ent) plenary_info = PlenaryMachineInfo(dbhw_ent, logger=logger) key = plenary_info.get_write_key() try: lock_queue.acquire(key) plenary_info.write(locked=True) if dbhw_ent.host and dbhw_ent.host.archetype.name != "aurora": dsdb_runner = DSDBRunner(logger=logger) dsdb_runner.update_host(dbhw_ent, oldinfo) dsdb_runner.commit_or_rollback() except AquilonError, err: plenary_info.restore_stash() raise ArgumentError(err)
continue if iface.name in data["interfaces"]: # No change to the interface, just do some administration iface_by_name[iface.name] = iface name_by_iface[iface] = iface.name else: # We don't have an interface with the same name. Check if a # discovered interface has our IP, and rename the existing interface # if that's the case. delete_iface = True if iface.assignments: ip = iface.assignments[0].ip if ip in ip_to_iface: new_name = ip_to_iface[ip]["name"] iface2 = first_of(dbnetdev.interfaces, lambda i: i.name == new_name) if iface2 and iface2.assignments: # The target name already exists, it has other # addresses, we have no choice than delete and re-add # the addresses pass else: # If the target name already exists but has no # addresses, then we can delete it and rename the # current interface if iface2 and iface2 not in ifaces_to_delete: ifaces_to_delete.append(iface2) iface_by_name[new_name] = iface name_by_iface[iface] = new_name delete_iface = False
def render(self, session, logger, interface, machine, mac, model, vendor, boot, pg, autopg, comments, master, clear_master, default_route, rename_to, **arguments): """This command expects to locate an interface based only on name and machine - all other fields, if specified, are meant as updates. If the machine has a host, dsdb may need to be updated. The boot flag can *only* be set to true. This is mostly technical, as at this point in the interface it is difficult to tell if the flag was unset or set to false. However, it also vastly simplifies the dsdb logic - we never have to worry about a user trying to remove the boot flag from a host in dsdb. """ audit_results = [] dbhw_ent = Machine.get_unique(session, machine, compel=True) dbinterface = Interface.get_unique(session, hardware_entity=dbhw_ent, name=interface, compel=True) oldinfo = DSDBRunner.snapshot_hw(dbhw_ent) if arguments.get('hostname', None): # Hack to set an intial interface for an aurora host... dbhost = dbhw_ent.host if dbhost.archetype.name == 'aurora' and \ dbhw_ent.primary_ip and not dbinterface.addresses: assign_address(dbinterface, dbhw_ent.primary_ip, dbhw_ent.primary_name.network) # We may need extra IP verification (or an autoip option)... # This may also throw spurious errors if attempting to set the # port_group to a value it already has. if pg is not None and dbinterface.port_group != pg.lower().strip(): dbinterface.port_group = verify_port_group( dbinterface.hardware_entity, pg) elif autopg: dbinterface.port_group = choose_port_group( session, logger, dbinterface.hardware_entity) audit_results.append(('pg', dbinterface.port_group)) if master: if dbinterface.addresses: # FIXME: as a special case, if the only address is the # primary IP, then we could just move it to the master # interface. However this can be worked around by bonding # the interface before calling "add host", so don't bother # for now. raise ArgumentError("Can not enslave {0:l} because it has " "addresses.".format(dbinterface)) dbmaster = Interface.get_unique(session, hardware_entity=dbhw_ent, name=master, compel=True) if dbmaster in dbinterface.all_slaves(): raise ArgumentError( "Enslaving {0:l} would create a circle, " "which is not allowed.".format(dbinterface)) dbinterface.master = dbmaster if clear_master: if not dbinterface.master: raise ArgumentError("{0} is not a slave.".format(dbinterface)) dbinterface.master = None if comments: dbinterface.comments = comments if boot: # Should we also transfer the primary IP to the new boot interface? # That could get tricky if the new interface already has an IP # address... for i in dbhw_ent.interfaces: if i == dbinterface: i.bootable = True i.default_route = True else: i.bootable = False i.default_route = False if default_route is not None: dbinterface.default_route = default_route if not first_of(dbhw_ent.interfaces, lambda x: x.default_route): logger.client_info("Warning: {0:l} has no default route, hope " "that's ok.".format(dbhw_ent)) #Set this mac address last so that you can update to a bootable #interface *before* adding a mac address. This is so the validation #that takes place in the interface class doesn't have to be worried #about the order of update to bootable=True and mac address if mac: q = session.query(Interface).filter_by(mac=mac) other = q.first() if other and other != dbinterface: raise ArgumentError("MAC address {0} is already in use by " "{1:l}.".format(mac, other)) dbinterface.mac = mac if model or vendor: if not dbinterface.model_allowed: raise ArgumentError( "Model/vendor can not be set for a {0:lc}.".format( dbinterface)) dbmodel = Model.get_unique(session, name=model, vendor=vendor, machine_type='nic', compel=True) dbinterface.model = dbmodel if rename_to: rename_interface(session, dbinterface, rename_to) session.flush() session.refresh(dbhw_ent) plenary_info = PlenaryMachineInfo(dbhw_ent, logger=logger) key = plenary_info.get_write_key() try: lock_queue.acquire(key) plenary_info.write(locked=True) if dbhw_ent.host and dbhw_ent.host.archetype.name != "aurora": dsdb_runner = DSDBRunner(logger=logger) dsdb_runner.update_host(dbhw_ent, oldinfo) dsdb_runner.commit_or_rollback() except AquilonError, err: plenary_info.restore_stash() raise ArgumentError(err)
def render(self, session, logger, interface, machine, mac, model, vendor, boot, pg, autopg, comments, master, clear_master, default_route, rename_to, **arguments): """This command expects to locate an interface based only on name and machine - all other fields, if specified, are meant as updates. If the machine has a host, dsdb may need to be updated. The boot flag can *only* be set to true. This is mostly technical, as at this point in the interface it is difficult to tell if the flag was unset or set to false. However, it also vastly simplifies the dsdb logic - we never have to worry about a user trying to remove the boot flag from a host in dsdb. """ audit_results = [] dbhw_ent = Machine.get_unique(session, machine, compel=True) dbinterface = Interface.get_unique(session, hardware_entity=dbhw_ent, name=interface, compel=True) oldinfo = DSDBRunner.snapshot_hw(dbhw_ent) if arguments.get('hostname', None): # Hack to set an intial interface for an aurora host... dbhost = dbhw_ent.host if dbhost.archetype.name == 'aurora' and \ dbhw_ent.primary_ip and not dbinterface.addresses: assign_address(dbinterface, dbhw_ent.primary_ip, dbhw_ent.primary_name.network, logger=logger) # We may need extra IP verification (or an autoip option)... # This may also throw spurious errors if attempting to set the # port_group to a value it already has. if pg is not None and dbinterface.port_group != pg.lower().strip(): dbinterface.port_group = verify_port_group( dbinterface.hardware_entity, pg) elif autopg: dbinterface.port_group = choose_port_group( session, logger, dbinterface.hardware_entity) audit_results.append(('pg', dbinterface.port_group)) if master: if dbinterface.addresses: # FIXME: as a special case, if the only address is the # primary IP, then we could just move it to the master # interface. However this can be worked around by bonding # the interface before calling "add host", so don't bother # for now. raise ArgumentError("Can not enslave {0:l} because it has " "addresses.".format(dbinterface)) dbmaster = Interface.get_unique(session, hardware_entity=dbhw_ent, name=master, compel=True) if dbmaster in dbinterface.all_slaves(): raise ArgumentError("Enslaving {0:l} would create a circle, " "which is not allowed.".format(dbinterface)) dbinterface.master = dbmaster if clear_master: if not dbinterface.master: raise ArgumentError("{0} is not a slave.".format(dbinterface)) dbinterface.master = None if comments: dbinterface.comments = comments if boot: # Figure out if the current bootble interface also has the # default route set; the new bootable interface probably # wants to have the same settings. Note that if # old_default_route is None there was no bootable interface. old_default_route = None for i in dbhw_ent.interfaces: if i.bootable == True: old_default_route = i.default_route break # Apply the bootable flag to the supplied interface, clearing # it on all other interfaces. for i in dbhw_ent.interfaces: if i == dbinterface: i.bootable = True else: i.bootable = False # If the user was not explicit about the default route flag # (default_route is None); there was an existing bootable # interface (old_default_route is not None); the new default # route setting differs from the old - then produce a warning. if (default_route is None and old_default_route is not None and dbinterface.default_route != old_default_route): if old_default_route: logger.client_info("Warning: New boot interface {0} is no " "longer provides the default route; it " "did before!".format(dbinterface)) else: logger.client_info("Warning: New boot interface {0} now " "provides the default route; it didn't " "before!".format(dbinterface)) # Should we also transfer the primary IP to the new boot interface? # That could get tricky if the new interface already has an IP # address... if default_route is not None: dbinterface.default_route = default_route if not first_of(dbhw_ent.interfaces, lambda x: x.default_route): logger.client_info("Warning: {0:l} has no default route, hope " "that's ok.".format(dbhw_ent)) #Set this mac address last so that you can update to a bootable #interface *before* adding a mac address. This is so the validation #that takes place in the interface class doesn't have to be worried #about the order of update to bootable=True and mac address if mac: q = session.query(Interface).filter_by(mac=mac) other = q.first() if other and other != dbinterface: raise ArgumentError("MAC address {0} is already in use by " "{1:l}.".format(mac, other)) dbinterface.mac = mac if model or vendor: if not dbinterface.model_allowed: raise ArgumentError("Model/vendor can not be set for a {0:lc}." .format(dbinterface)) dbmodel = Model.get_unique(session, name=model, vendor=vendor, model_type=NicType.Nic, compel=True) dbinterface.model = dbmodel if rename_to: rename_interface(session, dbinterface, rename_to) session.flush() plenaries = PlenaryCollection(logger=logger) plenaries.append(Plenary.get_plenary(dbhw_ent)) # Interface renaming affects the host and service addresses if dbhw_ent.host: plenaries.append(Plenary.get_plenary(dbhw_ent.host)) for addr in dbinterface.assignments: if addr.service_address: plenaries.append(Plenary.get_plenary(addr.service_address)) with plenaries.get_key(): try: plenaries.write(locked=True) if dbhw_ent.host and dbhw_ent.host.archetype.name != "aurora": dsdb_runner = DSDBRunner(logger=logger) dsdb_runner.update_host(dbhw_ent, oldinfo) dsdb_runner.commit_or_rollback() except AquilonError, err: plenaries.restore_stash() raise ArgumentError(err) except: