Exemple #1
0
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()
Exemple #2
0
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, ""
Exemple #3
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)
Exemple #4
0
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
Exemple #5
0
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
Exemple #6
0
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
Exemple #7
0
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
Exemple #8
0
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
Exemple #9
0
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
Exemple #10
0
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