def validate_label(label): """Make sure the label is not in use Args: label: proposed new label Returns: rc: return code 0 if all ok 101 if label already in use message: error message associated with failure """ try: session = persistent_mgr.create_database_session() devices_info = persistent_mgr.get_all_devices(session) for device in devices_info: if device.label == label: error_message = _( "The label '%s' that is specified is already being used by " "another device or virtual machine in the network.") % ( label) return 101, error_message return 0, "" finally: session.close()
def validate_address(address): """Make sure the address is a valid IPv4 address and is not in use Args: address: proposed new IPv4 Address Returns: rc: return code 0 if IP address is valid 111 if IP address is invalid form 108 if IP address is already in use by another inventoried system. """ _method_ = "resource_mgr.validate_address" if not is_valid_address(address): logging.error("%s::IP address is invalid (%s).", _method_, address) message = _("IP address is invalid (%s).") % (address) return 111, message try: session = persistent_mgr.create_database_session() if _check_device_exist(session, address): error_message = _( "The IP address '%s' that is specified is already being used by" " another device or virtual machine in the network.") % ( address) return 108, error_message finally: session.close() return 0, ""
def add_resource_roles(resource_label=None, resource_id=None, roles=None, additional_data=None): """ And roles to an existing resource """ message = None if roles is None: roles = [] session = persistent_mgr.create_database_session() if resource_id is not None: pass elif resource_label is not None: resource = persistent_mgr.get_device_by_label(session, resource_label) if resource is not None: resource_id = resource.resource_id else: message = "Error: add_role called without specifying to remove either a label or id" return -1, message roles_to_add = [] for role in roles: roles_to_add.append(ResourceRole(resource_id, role, additional_data)) hooks = _load_inventory_device_plugins() hook_name = 'unknown' # keeps pylint happy # pre_save hooks try: for hook_name, hook_plugin in hooks.items(): hook_plugin.add_role_pre_save(resource, roles_to_add) except Exception as e: logging.exception(e) message = _("Before role was added. Error in plugin (%s): %s") % ( hook_name, e) persistent_mgr.add_device_roles(session, roles_to_add) # post_save hooks try: for hook_name, hook_plugin in hooks.items(): hook_plugin.add_role_post_save(resource, roles_to_add) except Exception as e: logging.exception(e) message = _("After role was added. Error in plugin (%s): %s") % ( hook_name, e) session.close() if message is None: message = _("added role successfully.") return (0, message)
def get_resource_id_by_label(resource_label): """ Find the resource id for the given label Returns: resource_id or None """ resource_id = None session = persistent_mgr.create_database_session() resource = persistent_mgr.get_device_by_label(session, resource_label) if resource: resource_id = resource.resource_id session.close() return resource_id
def remote_access(label): """Establish ssh shell access to remote endpoint Args: label: label of the device to establish shell with Returns: rc: return code message: message associated with return code returned """ _method_ = 'remote_access.remote_access' session = persistent_mgr.create_database_session() device = persistent_mgr.get_device_by_label(session, label) if device: address = device.address userid = device.userid password = None if device.password: password = persistent_mgr.decrypt_data(device.password) ssh_key_string = None key = device.key if key: ssh_key_string = StringIO(key.value) if key.password: password = persistent_mgr.decrypt_data(key.password) logging.info( "%s::Retrieved device details. Opening remote shell to the device (%s).", _method_, label) try: print(_( "Establishing remote SSH connection to device (%s).") % label) _create_remote_connection(label, address, userid, password, ssh_key_string) except Exception as e: message = _("Remote access to device (%s) failed due to error :%s") % ( label, e) logging.warning( "%s::Failed to connect to device (%s) failed due to error :%s", _method_, label, e) return 1, message else: message = _( "Device (%s) not found.") % label logging.warning( "%s::Device (%s) not found.", _method_, label) return 1, message logging.info( "%s::Remote access to device (%s) successful", _method_, label) message = _("Remote access to device (%s) successful") % label session.close() return 0, message
def remove_resource(labels=None, all_devices=False, deviceids=None): '''Remove devices based on information present in the arguments If the option deviceIDs is specified, then the options labels and all_devices will be ignored. If the option labels is specified then the all_devices option will be ignored. Args: labels List of labels of devices to remove all_devices indicate all devices to be removed. deviceids list of device ids to remove Returns: ret return code message message if provided with return code ''' not_found_values = [] session = persistent_mgr.create_database_session() if labels or deviceids: all_devices = False # get devices based on labels and device ids if deviceids is not None: devices, not_found_values = persistent_mgr.get_devices_by_ids( session, deviceids) elif labels is not None: devices, not_found_values = persistent_mgr.get_devices_by_labels( session, labels) elif all_devices: devices = persistent_mgr.get_all_devices(session) else: message = \ ("Error: remove_device called without specifying to remove either a label, id or all") return -1, message hooks = _load_inventory_device_plugins() hook_name = 'unknown' # keeps pylint happy message = None remove_devices = [] not_remove_devices = [] for device in devices: try: for hook_name, hook_plugin in hooks.items(): hook_plugin.remove_device_pre_save(device) except Exception as e: logging.exception(e) message += _( "Error in plugin (%s). Unable to remove resource: Reason: %s" ) % (hook_name, e) not_remove_devices.append(device) continue remove_devices.append(device) ret = 0 if len(remove_devices) > 0: persistent_mgr.delete_devices(session, remove_devices) labels_message = get_labels_message(remove_devices) message = push_message(message, _("devices removed: %s.") % labels_message) # Call hook for remove_device_post_save for device in remove_devices: try: for hook_name, hook_plugin in hooks.items(): hook_plugin.remove_device_post_save(device) except Exception as e: logging.exception(e) message = push_message( message, _("After device was removed. Error in plugin " "(%s): %s") % (hook_name, e)) if len(not_remove_devices) > 0: labels_message = get_labels_message(not_remove_devices) message = push_message(message, _("devices not removed: %s.") % labels_message) ret = 102 if len(not_found_values) > 0: labels_message = get_labels_message(not_found_values) message = push_message(message, _("devices not found: %s") % labels_message) ret = 101 session.close() return ret, message
def list_resources(labels=None, isbriefly=False, device_types=None, deviceids=None, list_device_id=False, is_detail=False, racks=None): """Get a list of devices based on the information present in that arguments. Device ID's will override labels. labels or device ids will limit response to those items. Args: labels: list of labels to get device info for. isbriefly: indicates if brief response desired (defaults to just labels) device_types: list of device types to limit return device information to. deviceids: list_device_id: to include the device ID in the returned data set to True is_detail: Set to true to include detailed information for the object racks: list of rack identifiers containing rack ids Returns: integer with return code dictionary with results based on parameters Dictionary entries: message: any message returned for the processing of this method column_titles: dictionary of column titles accessed via the tag name they represent. devices: list of device information packed in a dictionary structure racks: list of rack information packed in a dictionary structure """ _method_ = 'resource_mgr.list_resource' logging.debug("ENTRY %s", _method_) all_tags = [ 'resourceid', 'label', 'rackid', 'rack-eia-location', 'machine-type-model', 'serial-number', 'ip-address', 'hostname', 'userid', 'version', 'architecture', 'resource-type', 'status', 'statusTime', 'web_url', 'auth_method', 'capabilities', 'roles' ] brief_tags = ['label'] result = {} session = persistent_mgr.create_database_session() # get the list of device types requested as an array device_types_array = device_types # get the rack ids requested as an array rack_ids_array = racks # decide the set of data to return tags = all_tags if is_detail: isbriefly = False if isbriefly: tags = brief_tags # include deviceid info in returned data if requested. if list_device_id: tags.insert(0, 'resourceid') # get devices based on labels and device ids if deviceids is not None: devices, _not_found_values = persistent_mgr.get_devices_by_ids( session, deviceids) elif labels is not None: devices, _not_found_values = persistent_mgr.get_devices_by_labels( session, labels) else: devices = persistent_mgr.get_all_devices(session) # check if labels returned anything if specified if len(devices) == 0 and labels: message = _("No device labeled as \'%s\'") % labels result['message'] = message logging.debug("EXIT %s label not found", _method_) return 101, result logging.debug("%s: before filtering", _method_) # possibly filter by device types if specified filtered_result_devices = [] if device_types_array: for device in devices: if device.resource_type in device_types_array: filtered_result_devices.append(device) else: filtered_result_devices = devices # possibly filter by rack ids rack_filtered_devices = [] if rack_ids_array: for device in filtered_result_devices: if device.rack_id in rack_ids_array: rack_filtered_devices.append(device) else: rack_filtered_devices = filtered_result_devices logging.debug("%s: before add table info", _method_) # add table column info table_columns_titles = [] result['column_tags'] = tags for tag in tags: table_columns_titles.append(_get_devicetag_text_id(tag)) result['column_titles'] = table_columns_titles logging.debug("%s: before add devices to output", _method_) result_devices = [] plugins = _load_device_plugins() for device in rack_filtered_devices: device_dict = device.to_dict_obj() device_output = {} for tag in tags: tag_value = device_dict.get(tag) if tag == 'machine-type-model' or tag == 'serial-number': tag_value = tag_value.replace(',', ' ') device_output[tag] = tag_value # add the web url for the device plugin = plugins[device.resource_type] web_url = plugin.get_web_url(device.address) device_output["web_url"] = web_url # figure out the if it's logging and monitoring capable device_output["capabilities"] = plugin.get_capabilities() # figure out the roles this device plays roles = [] for device_role in persistent_mgr.get_device_roles_by_device_id( session, device.resource_id): roles.append(device_role.role) device_output["roles"] = roles # add the auth_method for the device if device.key: auth_method = constants.auth_method.SSH_KEY_AUTHENTICATION.value else: auth_method = constants.auth_method.USERID_PASSWORD.value device_output["auth_method"] = auth_method # add final form of device info to result result_devices.append(device_output) result['resources'] = result_devices message = "" result['message'] = message logging.debug("EXIT %s normal", _method_) session.close() return 0, result
def add_resource(label, device_type, address, userid, password, rackid='', rack_location='', ssh_key=None, offline=False): """ Add device to the list of devices in the configuration managed Args: label: label for device device_type: type of device from device enumeration address: IP address of device userid: string with device userid password: string with device password (or password for ssh key) rackid: string identify rack id, if not specified will default to management rack rack:_location string identifying rack location ssh_key: ssh key string offline: Add the resource even if it can't be contacted Returns: RC: integer return code Message: string with message associated with return code """ _method_ = 'resource_mgr.add_resource' label = label.strip() address = address.strip() session = persistent_mgr.create_database_session() if not offline: ipv4, hostname = _check_address(address) else: ipv4 = address hostname = "" # adding default hostname for cases where dns doesn't resolve the address # we need *some* hostname to use on Nagios configuration if hostname == "": hostname = address rc, message = validate_address(ipv4) if rc != 0: return rc, message rc, message = validate_label(label) if rc != 0: return rc, message if not offline: (validate_ret, device_type, mtm, serialnum, version, architecture) = validate(ipv4, userid, password, device_type, ssh_key) if validate_ret != 0: logging.error( "%s::failed to add device, validate device(%s) return value(%d).", _method_, label, validate_ret) error_message = None if validate_ret == 1: error_message = _("Failed to connect the device.") elif validate_ret == 2: error_message = _( "The userid/password combination is not valid.") elif validate_ret == 3: error_message = _( "No plugin capable of managing device was found.") elif validate_ret == 109: error_message = _("Connect timeout.") return validate_ret, error_message else: if _check_device_exist_by_props(session, device_type, mtm, serialnum): logging.error( "%s::failed to add device, device(machine-type-model=%s, " "serial-number=%s) is already managed.", _method_, mtm, serialnum) error_message = _( "The device is not added, a device with the same serial number " "and machine type model is found in the configuration file." ) return 110, error_message # figure out the rack ID to add the device under if rackid: rack = persistent_mgr.get_rack_by_id(session, rackid) else: # don't have a rack id. find first the rack and assign it there try: racks_info = persistent_mgr.get_all_racks(session) rack = racks_info[0] except IndexError: # No rack exist, create one rack = Rack() rack.label = "Default" persistent_mgr.add_racks(session, [rack]) device_info = Resource() device_info.rack = rack device_info.eia_location = rack_location device_info.machine_type_model = mtm device_info.serial_number = serialnum device_info.address = ipv4 device_info.hostname = hostname device_info.userid = userid if password and not ssh_key: device_info.password = persistent_mgr.encrypt_data(password) device_info.label = label device_info.resource_type = device_type device_info.version = version device_info.architecture = architecture device_info.status = constants.access_status.SUCCESS.value device_info.statusTime = datetime.utcnow() # we are adding the device after validation, set validated. device_info.validated = True hooks = _load_inventory_device_plugins() hook_name = 'unknown' # keeps pylint happy try: for hook_name, hook_plugin in hooks.items(): hook_plugin.add_device_pre_save(device_info) except Exception as e: logging.exception(e) message = _("Before device was added. Error in plugin (%s): %s") % ( hook_name, e) return 102, message persistent_mgr.add_devices(session, [device_info]) if ssh_key: key_info = Key() key_info.resource = device_info key_info.type = "RSA" key_info.value = ssh_key if password: key_info.password = persistent_mgr.encrypt_data(password) persistent_mgr.add_ssh_keys(session, [key_info]) try: for hook_name, hook_plugin in hooks.items(): hook_plugin.add_device_post_save(device_info) except Exception as e: logging.exception(e) message = _("After device was added. Error in plugin (%s): %s") % ( hook_name, e) if not message: message = _("Added device successfully.") session.close() return 0, message
def change_resource_properties(label=None, deviceid=None, new_label=None, userid=None, password=None, address=None, rackid=None, rack_location=None, ssh_key=None): """ Change the device properties in the data store Args: label: the existing label of the device (this or device id should be provided) deviceid: the device id of the device to change new_label: new label to set for the device userid: the userid to set as userid managing the device. password: password of the userid or the ssh key address: the ip address or the hostname to set for the device rackid: rack id to set for the device rack_location: location in the rack of the element ssh_key: string containing the new ssh private key Returns: rc: return code message: completion message indicating reason for non zero rc (translated) """ _method_ = 'resource_mgr.change_resource_properties' message = None session = persistent_mgr.create_database_session() # no properties changed properties = [ new_label, userid, password, address, rackid, rack_location, ssh_key ] if all(prop is None for prop in properties): return 0, "" # gain access to the device object for the targeted item. if deviceid is not None: device = persistent_mgr.get_device_by_id(session, deviceid) device_des = deviceid else: device = persistent_mgr.get_device_by_label(session, label) device_des = label if not device: logging.error( "%s::Failed to change device properties device (%s) is not found.", _method_, device_des) message = _( "Failed to change device properties, device (%s) is not found." ) % (device_des) return 101, message old_device_info = device.to_dict_obj() address_changed = False # check if we now need to handle an IP address change in the change properties ip_address = "" hostname = "" if address is not None: if is_valid_address(address): ip_address = address hostname = socket.gethostbyaddr(address)[0] else: hostname = socket.getfqdn(address) ip_address = socket.gethostbyname(hostname) if ip_address != device.address: # check if id is of good form and not already in use as long as its # different from the one we have rc, message = validate_address(ip_address) if rc != 0: logging.error("%s::Failed to validate supplied address: %s", _method_, ip_address) return rc, message else: # now handle the IP address change address_changed = True logging.info("%s: IP address changed.", _method_) device.address = ip_address device.hostname = hostname else: # we may need the address for authorization changes, make sure its set ip_address = device.address # if we made it here we, have an ip address to use and maybe using a # changed address. old_auth = None new_auth = None if address_changed or userid is not None or password is not None or ssh_key is not None: # validate that the existing credentials work with the new IP # address or the new credentials are valid # Figure out if we are: # 1. Replacing the userid and password with another userid and pasword # 2. Replacing the ssh_key with another ssh_key (may or may not have a password) # 3. Replacing the userid and password with an ssh_key # 4. Replacing the ssh_key with a userid nad password # 5. Not changing anything just the ip address # Figure out and set old_auth and new_auth to either userpass or key if device.key is not None: old_auth = "key" else: old_auth = "userpass" if ssh_key is not None: new_auth = "key" elif userid is not None or password is not None: new_auth = "userpass" else: new_auth = None device_type = device.resource_type if userid: temp_userid = userid else: temp_userid = device.userid temp_password = None temp_ssh_key = None if password: temp_password = password else: if device.password is not None: if new_auth is None: # only lookup old password if auth hasn't changed temp_password = persistent_mgr.decrypt_data( device.password) if ssh_key: temp_ssh_key = ssh_key else: if device.key: key = device.key temp_ssh_key = key.value if key.password: if new_auth is None: # only lookup old password if auth hasn't changed temp_password = persistent_mgr.decrypt_data( key.password) if new_auth == "key": rc, message = _change_device_key(device, ip_address, temp_userid, temp_ssh_key, temp_password) elif new_auth == "userpass": rc, message = _change_device_userpass(device, ip_address, temp_userid, temp_password) else: rc, message = _validate(ip_address, temp_userid, temp_password, device_type, temp_ssh_key) if rc != 0: # return error if unable to validate with currently set info return rc, message else: device.status = constants.access_status.SUCCESS.value device.statusTime = datetime.utcnow() if new_label is not None and new_label != device.label: # have new label and the new label differs from the existing label for # the target device rc, message = validate_label(new_label) if rc != 0: # another device already exists with the label logging.error( "%s::failed to change device properties, a device with the new label (%s)" " already exists.", _method_, new_label) message = _( "Failed to change device properties, a device with the new label" " (%(label)s) already exists.") % { 'label': new_label } return 104, message device.label = new_label if rackid is not None: device.rack_id = rackid if rack_location is not None: device.eia_location = rack_location # pre_save hooks hooks = _load_inventory_device_plugins() hook_name = 'unknown' # keeps pylint happy try: for hook_name, hook_plugin in hooks.items(): hook_plugin.change_device_pre_save(device, old_device_info) except Exception as e: logging.exception(e) message = _("Error in plugin (%s). Unable to change device: Reason: %s" ) % (hook_name, e) return 102, message # commit the change. logging.info("%s: commit device changes now. device info: %s", _method_, device) persistent_mgr.update_device(session) if old_auth == "key" and new_auth == "userpass": # Need to delete ssh key from database key_info = device.key persistent_mgr.delete_keys(session, [key_info]) # post_save hooks try: for hook_name, hook_plugin in hooks.items(): hook_plugin.change_device_post_save(device, old_device_info) except Exception as e: logging.exception(e) message = push_message( message, _("After device properties were changed, " "Error in plugin (%s): %s") % (hook_name, e)) # return success logging.info("EXIT %s device properties changed", _method_) message = push_message(message, _("Changed device successfully.")) session.close() return 0, message
def change_resource_password(label=None, deviceid=None, old_password=None, new_password=None): method_ = 'resource_mgr.change_resource_password' message = None session = persistent_mgr.create_database_session() # gain access to the device object for the targeted item. if deviceid is not None: device = persistent_mgr.get_device_by_id(session, deviceid) device_des = deviceid elif label is not None: label = label.strip() device = persistent_mgr.get_device_by_label(session, label) device_des = label else: logging.error("Deviceid and label are None.") message = _("Deviceid and label are None") return 101, message if not device: logging.error( "%s::Failed to change device password device (%s) is not found.", method_, device_des) message = _( "Failed to change device password, device (%s) is not found.") % ( device_des) return 101, message device_type = device.resource_type plugins = _load_device_plugins() if device_type: plugin = plugins[device_type] try: plugin.connect(device.address, device.userid, old_password) plugin.change_device_password(new_password) plugin.disconnect() # Now change the password in the database device.password = persistent_mgr.encrypt_data(new_password) # Commit the change logging.info("%s: commit device changes now. device info: %s", method_, device) persistent_mgr.update_device(session) except KeyError: logging.error("%s::plugin(%s) not found", method_, device_type) message = _( "Failed to change device password, plugin (%s) is not found." ) % (device_type) return 101, message except Exception as e: logging.exception(e) logging.warning( "%s:plugin. Exception running change_device_password: %s", method_, e) message = _( "Failed to change device password, Exception occurred for plugin (%s)." ) % (device_type) return 101, message if not message: message = _("Changed device password successfully.") session.close() return 0, message