示例#1
0
def main():
    """
    Main.

    Returns
    -------
        int
            Return value of the operation, if any.
            0 otherwise.
    """

    parser = get_args_parser()
    args = parser.parse_args()
    if args.command is None:
        # default to 'sync' command
        args.command = "sync"

    if args.command == 'usage':
        parser.print_help()
        sys.exit(0)

    oci_sess = None
    try:
        oci_sess = oci_utils.oci_api.OCISession()
    except Exception as e:
        _logger.debug('Cannot get OCI session: %s', str(e))

    system_disks = lsblk.list()
    iscsiadm_session = iscsiadm.session()

    if args.command == 'show':
        display_current_devices(oci_sess, iscsiadm_session, system_disks)
        if args.compartments:
            api_display_available_block_volumes(oci_sess, args.compartments,
                                                args.all)
        else:
            api_display_available_block_volumes(oci_sess, None, args.all)
        return 0

    max_volumes = OCIUtilsConfiguration.getint('iscsi', 'max_volumes')
    if max_volumes > oci_utils._MAX_VOLUMES_LIMIT:
        _logger.error("Your configured max_volumes(%s) is over the limit(%s)",
                      max_volumes, oci_utils._MAX_VOLUMES_LIMIT)
        max_volumes = oci_utils._MAX_VOLUMES_LIMIT

    ocid_cache = load_cache(iscsiadm.ISCSIADM_CACHE,
                            max_age=timedelta(minutes=2))[1]
    if ocid_cache is None:
        _logger.debug('updating the cache')
        # run ocid once, to update the cache
        ocid_refresh(wait=True)
        # now try to load again
        ocid_cache = load_cache(iscsiadm.ISCSIADM_CACHE,
                                max_age=timedelta(minutes=2))[1]
    if ocid_cache is None:
        targets, attach_failed = None, None
    else:
        targets, attach_failed = ocid_cache

    detached_volume_iqns = load_cache(__ignore_file)[1]
    if detached_volume_iqns is None:
        detached_volume_iqns = []

    if args.command == 'sync' and not detached_volume_iqns and not attach_failed:
        # nothing to do, stop here
        print("All known devices are attached.")
        print("Use the -s or --show option for details.")

    # starting from here, nothing works if we are not root
    _user_euid = os.geteuid()
    if _user_euid != 0:
        _logger.error("You must run this program with root privileges")
        return 1

    if args.command == 'sync':
        # we still have volume not attached, process them.
        retval = 0
        _did_something = False
        if detached_volume_iqns:
            print()
            print("Detached devices:")
            for iqn in detached_volume_iqns:
                display_detached_iscsi_device(iqn, targets)
                if args.apply or args.interactive:
                    if args.yes:
                        ans = True
                    else:
                        ans = ask_yes_no(
                            "Would you like to attach this device?")
                    if ans:
                        try:
                            _do_iscsiadm_attach(oci_sess, iqn, targets)
                            _did_something = True
                        except Exception as e:
                            _logger.error('[%s] attachment failed: %s', iqn,
                                          str(e))
                            retval = 1

        if attach_failed:
            _logger.info("Devices that could not be attached automatically:")
            for iqn in list(attach_failed.keys()):
                display_detached_iscsi_device(iqn, targets, attach_failed)
                _attach_user_name = None
                _attach_user_passwd = None
                _give_it_a_try = False
                if args.apply or args.interactive:
                    if attach_failed[iqn] != 24:
                        # not authentication error
                        if args.yes or ask_yes_no(
                                "Would you like to retry attaching this device?"
                        ):
                            _give_it_a_try = True
                    else:
                        # authentication error
                        if args.yes or ask_yes_no(
                                "Would you like to configure this device?"):
                            _give_it_a_try = True
                            if oci_sess is not None:
                                oci_vols = oci_sess.find_volumes(iqn=iqn)
                                if len(oci_vols) != 1:
                                    _logger.error('volume [%s] not found', iqn)
                                    _give_it_a_try = False
                                _attach_user_name = oci_vols[0].get_user()
                                _attach_user_passwd = oci_vols[0].get_password(
                                )
                            else:
                                (_attach_user_name,
                                 _attach_user_passwd) = get_chap_secret(iqn)
                                if _attach_user_name is None:
                                    _logger.error(
                                        'Cannot retreive chap credentials')
                                    _give_it_a_try = False
                    if _give_it_a_try:
                        try:
                            _do_iscsiadm_attach(iqn, targets,
                                                _attach_user_name,
                                                _attach_user_passwd)
                            _did_something = True
                        except Exception as e:
                            _logger.error(
                                "Failed to configure device automatically: %s",
                                str(e))
                            retval = 1

        if _did_something:
            ocid_refresh()
        return retval

    if args.command == 'create':
        if len(system_disks) > max_volumes:
            _logger.error("This instance reached the max_volumes(%s)",
                          max_volumes)
            return 1
        try:
            do_create_volume(oci_sess,
                             size=args.size,
                             display_name=args.volume_name,
                             attach_it=args.attach_volume)
        except Exception as e:
            _logger.error('volume creation has failed: %s', str(e))
            return 1

        if args.show:
            display_current_devices(oci_sess, iscsiadm_session, system_disks)
            api_display_available_block_volumes(oci_sess)
        return 0

    if args.command == 'destroy':
        # destroy command used to be for only one volume
        # changed the behavior to be more aligned with attach/dettach commands
        # i.e : taking more than one ocid and doing best effort
        retval = 0
        if not args.yes:
            for ocid in args.ocids:
                _logger.info("volume : %s", ocid)
            if not ask_yes_no(
                    "WARNING: the volume(s) will be destroyed.  This is irreversible.  Continue?"
            ):
                return 0
        for ocid in args.ocids:
            try:
                _logger.debug('Destroying [%s]', ocid)
                do_destroy_volume(oci_sess, ocid)
                _logger.info("Volume [%s] is destroyed", ocid)
            except Exception as e:
                _logger.error('volume [%s] deletion has failed: %s', ocid,
                              str(e))
                retval = 1

        if args.show:
            display_current_devices(oci_sess, iscsiadm_session, system_disks)
            api_display_available_block_volumes(oci_sess)
        return retval

    if args.command == 'detach':
        retval = 0
        for iqn in args.iqns:
            if iqn in detached_volume_iqns:
                _logger.error("Target %s is already detached", iqn)
                retval = 1
                continue
            if iqn not in iscsiadm_session or 'device' not in iscsiadm_session[
                    iqn]:
                _logger.error("Target %s not found", iqn)
                retval = 1
                continue

            _logger.debug('unmounting the block volume')
            if not unmount_device(iscsiadm_session, iqn, system_disks):
                _logger.debug('Unmounting has failed')
                if not args.force:
                    if not ask_yes_no(
                            "Failed to unmount volume, Continue detaching anyway?"
                    ):
                        continue
                else:
                    _logger.info(
                        'unmount failed, force option selected,continue anyway'
                    )
            try:
                _logger.debug('Detaching [%s]', iqn)
                do_detach_volume(oci_sess, iscsiadm_session, iqn)
                _logger.info("Volume [%s] is detached", iqn)
                detached_volume_iqns.append(iqn)
            except Exception as e:
                _logger.error('volume [%s] detach has failed: %s', iqn, str(e))
                retval = 1
        if args.show:
            display_current_devices(oci_sess, iscsiadm_session, system_disks)
            api_display_available_block_volumes(oci_sess)

        _logger.info("Updating detached volume cache file: %s",
                     detached_volume_iqns)
        write_cache(cache_content=detached_volume_iqns,
                    cache_fname=__ignore_file)
        _logger.debug('trigger ocid refresh')
        ocid_refresh()

        return retval

    if args.command == 'attach':
        if len(system_disks) > max_volumes:
            _logger.error(
                "This instance reached the maximum number of volumes attached (%s)",
                max_volumes)
            return 1

        retval = 0

        for iqn in args.iqns:
            _iqn_to_use = iqn
            _save_chap_cred = False
            if iqn in iscsiadm_session:
                _logger.info("Target %s is already attached.", iqn)
                continue

            if _iqn_to_use.startswith('ocid1.volume.oc'):
                _logger.debug('given IQN [%s] is an ocid, attaching it',
                              _iqn_to_use)
                bs_volume = None
                try:
                    bs_volume = _do_attach_oci_block_volume(
                        oci_sess, _iqn_to_use)
                    _logger.info("Volume [%s] is attached", _iqn_to_use)
                    # user/pass coming from volume itself
                    _attachment_username = bs_volume.get_user()
                    _attachment_password = bs_volume.get_password()
                    _iqn_to_use = bs_volume.get_iqn()
                except Exception as e:
                    _logger.error('Failed to attach volume [%s]: %s',
                                  _iqn_to_use, str(e))
                    retval = 1
                    continue
            else:
                _logger.debug('given IQN [%s] is not an ocid', _iqn_to_use)
                if args.username is not None and args.password is not None:
                    _attachment_username = args.username
                    _attachment_password = args.password
                else:
                    # user/pass not provided , asking for it
                    (_attachment_username,
                     _attachment_password) = get_chap_secret(iqn)
                    _save_chap_cred = True

            _logger.debug('attaching [%s] to iSCSI session', _iqn_to_use)
            try:
                _do_iscsiadm_attach(_iqn_to_use,
                                    targets,
                                    user=_attachment_username,
                                    passwd=_attachment_password,
                                    iscsi_portal_ip=bs_volume.get_portal_ip())
                _logger.debug('attach ok')
                if _iqn_to_use in detached_volume_iqns:
                    detached_volume_iqns.remove(_iqn_to_use)
            except Exception as e:
                _logger.error("Failed to attach target %s: %s", _iqn_to_use,
                              str(e))
                _save_chap_cred = False
                retval = 1
                continue

            if _save_chap_cred:
                _logger.debug('attachment OK: saving chap creds')
                save_chap_secret(_iqn_to_use, _attachment_username,
                                 _attachment_password)

        if args.show:
            display_current_devices(oci_sess, iscsiadm_session, system_disks)
            api_display_available_block_volumes(oci_sess)

        if retval == 0:
            _logger.info("Updating detached volume cache file: %s",
                         detached_volume_iqns)
            write_cache(cache_content=detached_volume_iqns,
                        cache_fname=__ignore_file)
            _logger.debug('trigger ocid refresh')
            ocid_refresh()

        return retval

    if not args.show and not attach_failed and not detached_volume_iqns:
        print("All known devices are attached.")
        print("Use the -s or --show option for details.")

    return 0
def main():
    """
    Main.

    Returns
    -------
        int
            Return value of the operation, if any.
            0 otherwise.
    """
    global USE_OCI_SDK
    global oci_sdk_error
    global _user_euid
    oci_sdk_error = None
    oci_sess = None

    args = parse_args()

    _user_euid = os.geteuid()

    if oci_utils.oci_api.HAVE_OCI_SDK:
        try:
            oci_sess = oci_utils.oci_api.OCISession()
            USE_OCI_SDK = True
        except Exception as e:
            oci_sdk_error = str(e)
            USE_OCI_SDK = False
            if args.debug:
                raise

    if not os.path.isfile("/var/run/ocid.pid"):
        _logger.error("Warning:\n"
                      "For full functionality of this utility the ocid "
                      "service must be running\n"
                      "The administrator can start it using this command:\n"
                      "    sudo systemctl start ocid.service\n")

    max_volumes = OCIUtilsConfiguration.getint('iscsi', 'max_volumes')
    if max_volumes > oci_utils._MAX_VOLUMES_LIMIT:
        _logger.error(
            "Your configured max_volumes(%s) is over the limit(%s)\n"
            % (max_volumes, oci_utils._MAX_VOLUMES_LIMIT))
        max_volumes = oci_utils._MAX_VOLUMES_LIMIT

    ocid_cache = load_cache(iscsiadm.ISCSIADM_CACHE,
                            max_age=timedelta(minutes=2))[1]
    if ocid_cache is None and _user_euid == 0:
        # run ocid once, to update the cache
        ocid_refresh(wait=True, debug=args.debug)
        # now try to load again
        ocid_cache = load_cache(iscsiadm.ISCSIADM_CACHE,
                                max_age=timedelta(minutes=2))[1]
    if ocid_cache is None:
        targets, attach_failed = None, None
    else:
        targets, attach_failed = ocid_cache
    disks = lsblk.list()
    session = iscsiadm.session()
    detached = load_cache(__ignore_file)[1]
    if detached is None:
        detached = []

    if args.create_volume:
        if _user_euid != 0:
            _logger.error("You must run this program with root privileges "
                             "to create and attach iSCSI devices.\n")
            return 1
        if len(disks) > max_volumes:
            _logger.error(
                "This instance reached the max_volumes(%s)\n" % max_volumes)
            return 1

        # FIXME: use_chap
        retval = do_create_volume(oci_sess, size=args.create_volume,
                                  display_name=args.volume_name)
    elif args.destroy_volume:
        if _user_euid != 0:
            _logger.error("You must run this program with root privileges "
                             "to destroy a iSCSI volume.\n")
            return 1
        retval = do_destroy_volume(oci_sess, args.destroy_volume,
                                   args.interactive)
        if retval == 0:
            print "Volume %s is destroyed." % args.destroy_volume
        return retval

    elif args.detach_iqns:
        if _user_euid != 0:
            _logger.error("You must run this program with root privileges "
                             "to detach iSCSI devices.\n")
            return 1

        write_ignore_file = False
        retval = 0
        do_refresh = False
        for iqn in args.detach_iqns:
            if not iqn.startswith("iqn."):
                _logger.error("Invalid IQN %s\n" % iqn)
                retval = 1
                continue
            if iqn in detached:
                _logger.error("Target %s is already detached\n" % iqn)
                retval = 1
                continue
            if iqn not in session:
                _logger.error("Target %s not found\n" % iqn)
                retval = 1
                continue
            if 'boot:uefi' in iqn:
                _logger.error("IQN %s is the boot device, cannot "
                                 "detach.\n" % iqn)
                retval = 1
                continue
            if not unmount_device(session, iqn, disks):
                if args.interactive:
                    cont = ask_yes_no("Failed to unmount volume.  "
                                      "Continue detaching anyway?")
                    if not cont:
                        return 1
                else:
                    return 1

            api_detached = False

            if USE_OCI_SDK:
                api_detached = api_detach(oci_sess, iqn)

            if not iscsiadm.detach(session[iqn]['persistent_portal_ip'],
                                   session[iqn]['persistent_portal_port'],
                                   iqn):
                _logger.error("Failed to detach target %s\n" % iqn)
                retval = 1
            else:
                if not api_detached:
                    detached.append(iqn)
                    write_ignore_file = True
                    do_refresh = True
        if write_ignore_file:
            _logger.error("Updating ignore file: %s\n" % detached)
            write_cache(cache_content=detached,
                        cache_fname=__ignore_file)
        if do_refresh:
            ocid_refresh(debug=args.debug)
        return retval

    elif args.attach_iqns:
        if _user_euid != 0:
            _logger.error("You must run this program with root "
                             "privileges to attach iSCSI devices.\n")
            return 1

        if len(disks) > max_volumes:
            _logger.error(
                "This instance reached the max_volumes(%s)\n" % max_volumes)
            return 1

        retval = 0
        write_ignore_file = False
        do_refresh = False

        for iqn in args.attach_iqns:
            if iqn.startswith('ocid1.volume.oc'):
                # it's an OCID
                if not do_attach_ocid(oci_sess, iqn):
                    retval = 1
                continue
            elif not iqn.startswith("iqn."):
                _logger.error("Invalid IQN %s \n" % iqn)
                retval = 1
                continue

            if iqn in session:
                print "Target %s is already attached." % iqn
                continue
            if iqn not in detached and iqn not in attach_failed:
                _logger.error("Target %s not found\n" % iqn)
                retval = 1
                continue
            user = args.username
            passwd = args.password
            if user is None or passwd is None:
                (user, passwd) = get_chap_secret(iqn)
            if do_attach(oci_sess, iqn, targets,
                         user=user, passwd=passwd) != 0:
                _logger.error("Failed to attach target %s\n" % iqn)
                retval = 1
            else:
                do_refresh = True
                if iqn in detached:
                    detached.remove(iqn)
                if args.username is not None:
                    save_chap_secret(iqn, args.username, args.password)
                write_ignore_file = True
        if write_ignore_file:
            write_cache(cache_content=detached,
                        cache_fname=__ignore_file)
        if do_refresh:
            ocid_refresh(debug=args.debug)

        return retval

    if args.show:
        display_current_devices(oci_sess, session, disks)
        api_display_available_devices(oci_sess, args)

    if args.create_volume or args.destroy_volume:
        return retval

    if detached:
        print
        print "Detached devices:"

        do_refresh = False
        write_ignore_file = False
        for iqn in detached:
            display_detached_device(iqn, targets)
            if args.interactive:
                if _user_euid != 0:
                    print "You must run this program with root privileges " \
                          "to attach iSCSI devices.\n"
                    ans = False
                else:
                    ans = ask_yes_no("Would you like to attach this device?")
                if ans:
                    retval = do_attach(oci_sess, iqn, targets)
                    do_refresh = True
                    if retval == 24:
                        # authentication error
                        attach_failed[iqn] = 24
                    if iqn in detached:
                        detached.remove(iqn)
                        write_ignore_file = True
        if write_ignore_file:
            write_cache(cache_content=detached,
                        cache_fname=__ignore_file)
        if do_refresh:
            ocid_refresh(debug=args.debug)

    if attach_failed:
        print
        print "Devices that could not be attached automatically:"

        auth_errors = 0
        for iqn in attach_failed.keys():
            if attach_failed[iqn] == 24:
                auth_errors += 1

        for iqn in attach_failed.keys():
            display_attach_failed_device(iqn, targets, attach_failed)
            do_refresh = False
            if args.interactive:
                if attach_failed[iqn] != 24:
                    # not authentication error
                    ans = True
                    while ans:
                        if _user_euid != 0:
                            print "You must run this program with root  " \
                                  "privileges to attach iSCSI devices.\n"
                            ans = False
                        else:
                            ans = ask_yes_no("Would you like to retry "
                                             "attaching this device?")
                        if ans:
                            retval = do_attach(oci_sess, iqn, targets)
                            if retval == 0:
                                ans = False
                                do_refresh = True
                        else:
                            ans = False
                else:
                    # authentication error
                    if _user_euid != 0:
                        print "You must run this program with root " \
                              "privileges to configure iSCSI devices.\n"
                        ans = False
                    else:
                        ans = ask_yes_no("Would you like to configure this "
                                         "device?")
                    if ans:
                        retval = 1
                        if USE_OCI_SDK:
                            # try and get the user and password from the API
                            retval = do_attach(oci_sess, iqn, targets,
                                               None, None)
                        else:
                            (user, passwd) = get_chap_secret(iqn)
                            if user is not None:
                                retval = do_attach(oci_sess, iqn, targets,
                                                   user, passwd)
                        if retval == 0:
                            print "Device configured automatically."
                            do_refresh = True
                        else:
                            myocid = get_instance_ocid()
                            while ans:
                                print "To find the CHAP username and " \
                                      "password for this device, go to"
                                print "https://console.us-phoenix-1." \
                                      "oraclecloud.com/#/a/compute/instances" \
                                      "/%s/disks?jt=listing" % \
                                      myocid
                                print "Select the Block Volume, then click " \
                                      "the \"iSCSI Commands & Information\" " \
                                      "button."
                                print "CHAP username:"******"CHAP password:"******"Attaching iSCSI device..."
                                retval = do_attach(oci_sess, iqn, targets,
                                                   user, passwd)
                                if retval != 0:
                                    ans = ask_yes_no("Would you like to try "
                                                     "again?")
                                else:
                                    ans = False
                                    do_refresh = True
        if do_refresh:
            ocid_refresh(debug=args.debug)
        if not args.interactive and auth_errors:
            print
            print "Use the -i or --interactive mode to configure " \
                  "devices that require authentication information"

    if not args.show and not attach_failed and not detached:
        print "All known devices are attached."
        print "Use the -s or --show option for details."

    return 0