python连接elasticsearch

news2024/11/28 19:03:56

问题一:urllib3.exceptions.ProtocolError: (‘Connection aborted.’, RemoteDisconnected(‘Remote end closed connection without response’))

协议写错了,是https

问题一:SSLError([SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain

import ssl
from elasticsearch import Elasticsearch

# 不验证ssl_context=context,6.1.3版本有用
# 6.1.3版本设置verify_certs=False没用
# 因为` verify_certs=False`在后续创建连接时还是会使用默认的ssl加载,需设置context才有用
context = ssl._create_unverified_context()
client = Elasticsearch(hosts="https://1.1.1.1:9200/", http_auth=('用户名', '密码'), ssl_context=context)

# 不验证  verify_certs=False ,8版本有用
# 8版本设置ssl_context没用
# 因为8版本直接使用verify_certs这个变量进行控制,即使传参时传了不需要验证的上下文,他自己还会根据verify_certs参数,
# 如果它是true就会更新对应的数据,False时,直接创建一个不需要验证的上下文,连接的时候把这个上下文传递过去,
# 8版本的在一开始transport传参时就进行了判断创建
client = Elasticsearch(hosts="https://1.1.1.1:9200/", http_auth=('用户名', '密码'), verify_certs=False)

结论

1、elasticsearch Python 6.1.3 使用verify_certs=False时,不会创建ssl上下文,等到连接时发现没有上下文会自动创建一个默认的上下文,因此指定了上下文会起作用。

C:\Users\admin\AppData\Local\Programs\Python\Python39\Lib\site-packages\elasticsearch\connection\http_urllib3.py

class Urllib3HttpConnection(Connection):
    """
    Default connection class using the `urllib3` library and the http protocol.

    :arg host: hostname of the node (default: localhost)
    :arg port: port to use (integer, default: 9200)
    :arg url_prefix: optional url prefix for elasticsearch
    :arg timeout: default timeout in seconds (float, default: 10)
    :arg http_auth: optional http auth information as either ':' separated
        string or a tuple
    :arg use_ssl: use ssl for the connection if `True`
    :arg verify_certs: whether to verify SSL certificates
    :arg ca_certs: optional path to CA bundle.
        See https://urllib3.readthedocs.io/en/latest/security.html#using-certifi-with-urllib3
        for instructions how to get default set
    :arg client_cert: path to the file containing the private key and the
        certificate, or cert only if using client_key
    :arg client_key: path to the file containing the private key if using
        separate cert and key files (client_cert will contain only the cert)
    :arg ssl_version: version of the SSL protocol to use. Choices are:
        SSLv23 (default) SSLv2 SSLv3 TLSv1 (see ``PROTOCOL_*`` constants in the
        ``ssl`` module for exact options for your environment).
    :arg ssl_assert_hostname: use hostname verification if not `False`
    :arg ssl_assert_fingerprint: verify the supplied certificate fingerprint if not `None`
    :arg maxsize: the number of connections which will be kept open to this
        host. See https://urllib3.readthedocs.io/en/1.4/pools.html#api for more
        information.
    :arg headers: any custom http headers to be add to requests
    :arg http_compress: Use gzip compression
    """
    def __init__(self, host='localhost', port=9200, http_auth=None,
            use_ssl=False, verify_certs=VERIFY_CERTS_DEFAULT, ca_certs=None, client_cert=None,
            client_key=None, ssl_version=None, ssl_assert_hostname=None,
            ssl_assert_fingerprint=None, maxsize=10, headers=None, ssl_context=None, http_compress=False, **kwargs):

        '''省略'''
        kw = {}

        # if providing an SSL context, raise error if any other SSL related flag is used
        if ssl_context and ( (verify_certs is not VERIFY_CERTS_DEFAULT) or ca_certs
                             or client_cert or client_key or ssl_version):
            warnings.warn("When using `ssl_context`, all other SSL related kwargs are ignored")

        # if ssl_context provided use SSL by default
        if ssl_context and self.use_ssl:
            pool_class = urllib3.HTTPSConnectionPool
            kw.update({
                'assert_fingerprint': ssl_assert_fingerprint,
                'ssl_context': ssl_context,
            })

        elif self.use_ssl:
            pool_class = urllib3.HTTPSConnectionPool
            kw.update({
                'ssl_version': ssl_version,
                'assert_hostname': ssl_assert_hostname,
                'assert_fingerprint': ssl_assert_fingerprint,
            })

            # If `verify_certs` is sentinal value, default `verify_certs` to `True`
            if verify_certs is VERIFY_CERTS_DEFAULT:
                verify_certs = True

            ca_certs = CA_CERTS if ca_certs is None else ca_certs
            # verify_certs为false则不会更新任何ssl的信息,下边又因为没有cert_reqs和上下文变量,
            # 导致创建了默认的上下文变量即VerifyMode.CERT_REQUIRED
            if verify_certs:
                if not ca_certs:
                    raise ImproperlyConfigured("Root certificates are missing for certificate "
                        "validation. Either pass them in using the ca_certs parameter or "
                        "install certifi to use it automatically.")

                kw.update({
                    'cert_reqs': 'CERT_REQUIRED',
                    'ca_certs': ca_certs,
                    'cert_file': client_cert,
                    'key_file': client_key,
                })
            else:
                warnings.warn(
                    'Connecting to %s using SSL with verify_certs=False is insecure.' % host)

		# 该处会调用下边的HTTPSConnectionPool
        self.pool = pool_class(host, port=port, timeout=self.timeout, maxsize=maxsize, **kw)

C:\Users\admin\AppData\Local\Programs\Python\Python39\Lib\site-packages\urllib3\connectionpool.py

class HTTPSConnectionPool(HTTPConnectionPool):
    """
    Same as :class:`.HTTPConnectionPool`, but HTTPS.

    :class:`.HTTPSConnection` uses one of ``assert_fingerprint``,
    ``assert_hostname`` and ``host`` in this order to verify connections.
    If ``assert_hostname`` is False, no verification is done.

    The ``key_file``, ``cert_file``, ``cert_reqs``, ``ca_certs``,
    ``ca_cert_dir``, ``ssl_version``, ``key_password`` are only used if :mod:`ssl`
    is available and are fed into :meth:`urllib3.util.ssl_wrap_socket` to upgrade
    the connection socket into an SSL socket.
    """

    scheme = "https"
    ConnectionCls = HTTPSConnection

    def __init__(
        self,
        host,
        port=None,
        strict=False,
        timeout=Timeout.DEFAULT_TIMEOUT,
        maxsize=1,
        block=False,
        headers=None,
        retries=None,
        _proxy=None,
        _proxy_headers=None,
        key_file=None,
        cert_file=None,
        cert_reqs=None,
        key_password=None,
        ca_certs=None,
        ssl_version=None,
        assert_hostname=None,
        assert_fingerprint=None,
        ca_cert_dir=None,
        **conn_kw
    ):

        HTTPConnectionPool.__init__(
            self,
            host,
            port,
            strict,
            timeout,
            maxsize,
            block,
            headers,
            retries,
            _proxy,
            _proxy_headers,
            **conn_kw
        )

        self.key_file = key_file
        self.cert_file = cert_file
        # 更新cert_reqs
        self.cert_reqs = cert_reqs
        self.key_password = key_password
        self.ca_certs = ca_certs
        self.ca_cert_dir = ca_cert_dir
        self.ssl_version = ssl_version
        self.assert_hostname = assert_hostname
        self.assert_fingerprint = assert_fingerprint

    def _prepare_conn(self, conn):
        """
        Prepare the ``connection`` for :meth:`urllib3.util.ssl_wrap_socket`
        and establish the tunnel if proxy is used.
        """

        if isinstance(conn, VerifiedHTTPSConnection):
        	# 调用创建ssl上下文变量
            conn.set_cert(
                key_file=self.key_file,
                key_password=self.key_password,
                cert_file=self.cert_file,
                cert_reqs=self.cert_reqs,
                ca_certs=self.ca_certs,
                ca_cert_dir=self.ca_cert_dir,
                assert_hostname=self.assert_hostname,
                assert_fingerprint=self.assert_fingerprint,
            )
            conn.ssl_version = self.ssl_version
        return conn

C:\Users\admin\AppData\Local\Programs\Python\Python39\Lib\site-packages\urllib3\connection.py

    def set_cert(
        self,
        key_file=None,
        cert_file=None,
        cert_reqs=None,
        key_password=None,
        ca_certs=None,
        assert_hostname=None,
        assert_fingerprint=None,
        ca_cert_dir=None,
        ca_cert_data=None,
    ):
        """
        This method should only be called once, before the connection is used.
        """
        # 如果没有传cert_reqs 会根据上下文获取,因为没有创建上下文,所以会用默认的VerifyMode.CERT_REQUIRED
        if cert_reqs is None:
            if self.ssl_context is not None:
                cert_reqs = self.ssl_context.verify_mode
            else:
                cert_reqs = resolve_cert_reqs(None)

        self.key_file = key_file
        self.cert_file = cert_file
        # 赋值,下边调用connect时会使用
        self.cert_reqs = cert_reqs

    def connect(self):
        # Add certificate verification
        conn = self._new_conn()
        hostname = self.host
        tls_in_tls = False

        if self._is_using_tunnel():
            if self.tls_in_tls_required:
                conn = self._connect_tls_proxy(hostname, conn)
                tls_in_tls = True

            self.sock = conn

            # Calls self._set_hostport(), so self.host is
            # self._tunnel_host below.
            self._tunnel()
            # Mark this connection as not reusable
            self.auto_open = 0

            # Override the host with the one we're requesting data from.
            hostname = self._tunnel_host

        server_hostname = hostname
        if self.server_hostname is not None:
            server_hostname = self.server_hostname

        is_time_off = datetime.date.today() < RECENT_DATE
        if is_time_off:
            warnings.warn(
                (
                    "System time is way off (before {0}). This will probably "
                    "lead to SSL verification errors"
                ).format(RECENT_DATE),
                SystemTimeWarning,
            )

        # Wrap socket using verification with the root certs in
        # trusted_root_certs
        default_ssl_context = False
        # 如果没有上下文变量,则会根据创建默认的上下文变量,导致出现验证
        if self.ssl_context is None:
            default_ssl_context = True
            self.ssl_context = create_urllib3_context(
                ssl_version=resolve_ssl_version(self.ssl_version),
                cert_reqs=resolve_cert_reqs(self.cert_reqs),
            )

        context = self.ssl_context
        context.verify_mode = resolve_cert_reqs(self.cert_reqs)
2、elasticsearch Python 8 直接使用verify_certs这个变量进行控制,即使传参时传了不需要验证的上下文,他自己还会根据verify_certs参数,如果它是true就会更新对应的数据,False时,直接创建一个不需要验证的上下文,连接的时候把这个上下文传递过去,8版本的在一开始transport传参时就进行了判断创建。

C:\Users\admin\Desktop\second\venv\Lib\site-packages\elastic_transport_node_http_urllib3.py
在这里插入图片描述
C:\Users\admin\Desktop\second\venv\Lib\site-packages\elastic_transport_node_http_urllib3.py

class Urllib3HttpNode(BaseNode):
    def __init__(self, config: NodeConfig):
		'''省略'''
        if config.scheme == "https":
            pool_class = HTTPSConnectionPool
            # 根据你的配置创建上下文,如果你传了上下文直接返回你自己的上下文,但是下边会根据verify_certs的值给你更新掉
            ssl_context = ssl_context_from_node_config(config) 
            kw["ssl_context"] = ssl_context  

            if config.ssl_assert_hostname and config.ssl_assert_fingerprint:
                raise ValueError(
                    "Can't specify both 'ssl_assert_hostname' and 'ssl_assert_fingerprint'"
                )
            elif config.ssl_assert_fingerprint:
                ssl_context.check_hostname = False
                ssl_context.verify_mode = ssl.CERT_NONE

                kw.update(
                    {
                        "assert_fingerprint": config.ssl_assert_fingerprint,
                        "assert_hostname": False,
                        "cert_reqs": "CERT_NONE",
                    }
                )

            else:
                kw["assert_hostname"] = config.ssl_assert_hostname

                # Convert all sentinel values to their actual default
                # values if not using an SSLContext.
                ca_certs = (
                    DEFAULT_CA_CERTS if config.ca_certs is None else config.ca_certs
                )
                # 就在这里根据verify_certs把你的上下文更新掉,cert_reqs为CERT_NONE即不需要验证
                if config.verify_certs:
                    if not ca_certs:
                        raise ValueError(
                            "Root certificates are missing for certificate "
                            "validation. Either pass them in using the ca_certs parameter or "
                            "install certifi to use it automatically."
                        )

                    kw.update(
                        {
                            "cert_reqs": "CERT_REQUIRED",
                            "ca_certs": ca_certs,
                            "cert_file": config.client_cert,
                            "key_file": config.client_key,
                        }
                    )
                else:
                    kw["cert_reqs"] = "CERT_NONE"
         '''省略'''

下边的代码是6.1.3版本的

大致看了一眼代码:

1、

client = Elasticsearch(hosts="https://ip:9200/", http_auth=('用户名', '密码'), ssl=True, verify_certs=False)

1.1、
C:\Users\admin\AppData\Local\Programs\Python\Python39\Lib\site-packages\elasticsearch\client_init_.py
在这里插入图片描述
1.1.1、
C:\Users\admin\AppData\Local\Programs\Python\Python39\Lib\site-packages\elasticsearch\transport.py
在这里插入图片描述
在这里插入图片描述
1.1.1.1、
C:\Users\admin\AppData\Local\Programs\Python\Python39\Lib\site-packages\elasticsearch\connection\http_urllib3.py
在这里插入图片描述
1.1.1.1.1
C:\Users\admin\AppData\Local\Programs\Python\Python39\Lib\site-packages\urllib3\util\request.py
在这里插入图片描述
设置的用户名密码就是在这里被翻译的
在这里插入图片描述

1.1.1.2、

        和上边1.1.1.1函数在同一个函数中
        if ssl_context and self.use_ssl:
            pool_class = urllib3.HTTPSConnectionPool
            kw.update({
                'assert_fingerprint': ssl_assert_fingerprint,
                'ssl_context': ssl_context,
            })

        elif self.use_ssl:
            pool_class = urllib3.HTTPSConnectionPool
            kw.update({
                'ssl_version': ssl_version,
                'assert_hostname': ssl_assert_hostname,
                'assert_fingerprint': ssl_assert_fingerprint,
            })

            # If `verify_certs` is sentinal value, default `verify_certs` to `True`
            if verify_certs is VERIFY_CERTS_DEFAULT:  # 不验证的话直接跳到else,不处理
                verify_certs = True

            ca_certs = CA_CERTS if ca_certs is None else ca_certs
            if verify_certs:
                if not ca_certs:
                    raise ImproperlyConfigured("Root certificates are missing for certificate "
                        "validation. Either pass them in using the ca_certs parameter or "
                        "install certifi to use it automatically.")

                kw.update({
                    'cert_reqs': 'CERT_REQUIRED',
                    'ca_certs': ca_certs,
                    'cert_file': client_cert,
                    'key_file': client_key,
                })
            else:
                warnings.warn(
                    'Connecting to %s using SSL with verify_certs=False is insecure.' % host)

1.2、
C:\Users\admin\AppData\Local\Programs\Python\Python39\Lib\site-packages\elasticsearch\transport.py
在这里插入图片描述
在这里插入图片描述
1.2.1、
C:\Users\admin\AppData\Local\Programs\Python\Python39\Lib\site-packages\elasticsearch\connection\http_urllib3.py
在这里插入图片描述
在这里插入图片描述
1.2.1.1、
C:\Users\admin\AppData\Local\Programs\Python\Python39\Lib\site-packages\urllib3\connectionpool.py
在这里插入图片描述
在这里插入图片描述
1.2.1.1.1

C:\Users\admin\AppData\Local\Programs\Python\Python39\Lib\site-packages\urllib3\connectionpool.py
在这里插入图片描述
1.2.1.1.1.1
C:\Users\admin\AppData\Local\Programs\Python\Python39\Lib\site-packages\urllib3\connection.py
在这里插入图片描述
在这里插入图片描述

1.2.1.2、
在这里插入图片描述
1.2.1.2.1
C:\Users\admin\AppData\Local\Programs\Python\Python39\Lib\site-packages\urllib3\connectionpool.py
在这里插入图片描述
1.2.1.2.1.1
C:\Users\admin\AppData\Local\Programs\Python\Python39\Lib\site-packages\urllib3\connection.py

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
1.2.1.2.1.1.1
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1218518.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

uni-app:如何配置uni.request请求的超时响应时间(全局+局部)

方法一&#xff1a;全局配置响应时间 一、进入项目的manifest.json的代码视图模块 二、写入代码 "networkTimeout": {"request": 5000 }, 表示现在request请求响应时间最多位5秒 方法二&#xff1a;局部设置响应时间 一、直接在uni.request中写入属性…

Redis7.2.3集群安装,新增节点,删除节点,分配哈希槽,常见问题

概念&#xff1a; 【Redis】高可用之三&#xff1a;集群&#xff08;cluster&#xff09; - 知乎 实操&#xff1a; Redis集群三种模式 主从模式 优势&#xff1a; 主节点可读可写 从节点只能读&#xff08;从节点从主节点同步数据&#xff09; 缺点&#xff1a; 当主节点…

UE基础篇八:平衡蓝图与C++的使用

一、蓝图转换C++ 案例结构: 1.1 蓝图和C++对比 1.2 将蓝图变量转C++ 现在C++中定义同样的类型

【分布式】BASE理论详解

一、什么是BASE理论&#xff1f; BASE理论是对分布式系统设计和处理的一种理论指导&#xff0c;相对于ACID&#xff08;原子性、一致性、隔离性和持久性&#xff09;这一强一致性模型&#xff0c;BASE更强调在分布式系统中牺牲强一致性以获得可用性和性能的平衡。 BASE 理论是…

《硅基物语.AI写作高手:从零开始用ChatGPT学会写作》《从零开始读懂相对论》

文章目录 《硅基物语.AI写作高手&#xff1a;从零开始用ChatGPT学会写作》内容简介核心精华使用ChatGPT可以高效搞定写作的好处如下 《从零开始读懂相对论》内容简介关键点书摘最后 《硅基物语.AI写作高手&#xff1a;从零开始用ChatGPT学会写作》 内容简介 本书从写作与ChatG…

Java和JavaScript是一样的技术吗?

目录 一、Java 是什么 二、JavaScript 是什么 三、Java 和 JavaScript 的区别 一、Java 是什么 Java是一种广泛使用的计算机编程语言&#xff0c;最初由Sun Microsystems&#xff08;后被Oracle收购&#xff09;于1995年发布。Java是一种面向对象的语言&#xff0c;设计初衷…

上海亚商投顾:沪指低开低走 抖音概念股逆势爆发

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 沪指昨日震荡调整&#xff0c;深成指跌超1%&#xff0c;创业板指跌超1.8%。抖音概念股逆势爆发&#xff0c;佳…

Kubernetes基础知识了解

一、Kubernetes简介 Kubernetes是一个轻便的和可扩展的开源平台&#xff0c;用于管理容器化应用和服务。通过Kubernetes能够进行应用的自动化部署和扩缩容。在Kubernetes中&#xff0c;会将组成应用的容器组合成一个逻辑单元以更易管理和发现。Kubernetes积累了作为Google生产…

内网离线安装elasticsearch、kibana

一、软件获取 elastic kibana 二、elastic安装 解压安装即可提前可改下配置文件&#xff0c;不然可能会出现内存分配错误 三、运行elastic 需要调试看信息的话&#xff0c;可在cmd窗口运行bat&#xff0c;就会打印输出信息了。 生产kibana token bin\elasticsearch-create…

web:[BUUCTF 2018]Online Tool

题目 打开页面显示如下&#xff0c;进行代码审计 上述代码主要功能是接收‘host’参数&#xff0c;后使用nmap扫描主机端口 首先检查是否存在HTTP_X_FORWARDED_FOR头&#xff0c;若存在&#xff0c;将值赋值给EMOTE_ADDR,是为了跟踪用户真实的IP地址 后用检查get‘host’是否…

【蓝桥杯 第十五届模拟赛 Java B组】训练题(A - I)

目录 A、求全是字母的最小十六进制数 B、Excel表格组合 C、求满足条件的日期 D、 取数字 - 二分 &#xff08;1&#xff09;暴力 &#xff08;2&#xff09;二分 E、最大连通块 - bfs F、哪一天&#xff1f; G、信号覆盖 - bfs &#xff08;1&#xff09;bfs&#xf…

UE基础篇七:特效

导语&#xff1a; 文末有工程地址&#xff0c;通过小游戏来学习特效 入门 下载项目&#xff0c;在文章最下面 按播放开始游戏。按住左键射击并使用W、A、S和D移动。 在本教程中&#xff0c;您将创建两个粒子效果。一个用于船舶的推进器&#xff0c;一个用于船舶爆炸时。要创…

从0开始学习JavaScript--JavaScript 循环与迭代详解

JavaScript中的循环和迭代是编写高效和灵活代码的关键。循环用于重复执行一段代码&#xff0c;而迭代则用于遍历数据结构。本文将深入研究JavaScript中常见的循环结构和迭代方法&#xff0c;并通过丰富的示例代码来帮助读者更好地理解和运用这些概念。 基本的for循环 for循环…

RT-Thread STM32F407 定时器

定时器简介 硬件定时器一般有 2 种工作模式&#xff0c;定时器模式和计数器模式。不管是工作在哪一种模式&#xff0c;实质都是通过内部计数器模块对脉冲信号进行计数。下面是定时器的一些重要概念。 计数器模式&#xff1a;对外部输入引脚的外部脉冲信号计数。 定时器模式&…

21 - 深入JVM即时编译器JIT,优化Java编译

说到编译&#xff0c;我猜你一定会想到 .java 文件被编译成 .class 文件的过程&#xff0c;这个编译我们一般称为前端编译。Java 的编译和运行过程非常复杂&#xff0c;除了前端编译&#xff0c;还有运行时编译。由于机器无法直接运行 Java 生成的字节码&#xff0c;所以在运行…

java springboot在当前测试类中添加临时属性 不影响application和其他范围

目前 我们的属性基本都写在 application.yml 里面了 但是 如果 我们只是想做一下临时变量的测试 有没有办法实现呢&#xff1f; 显然是有的 这里 我们还是先在application.yml中去写一个 test属性 下面加个prop 然后 我们尝试在测试类中 获取一下这个属性 直接用 Value 读取…

第七篇 基于JSP 技术的网上购书系统——新品上架、推荐产品、在线留言、搜索功能实现(网上商城、仿淘宝、当当、亚马逊)

目录 1.新品上架 1.1功能说明 1.2界面设计 1.3处理流程 1.4数据来源和算法 1.4.1数据来源 1.4.2查询条件 1.4.3表间关系 1.4.4相关sql实例 2.推荐产品 2.1功能说明 2.2界面设计 2.3处理流程 2.4数据来源和算法 2.4.1数据来源 2.4.2查询条件 2.4.3表间关…

【Spring】Spring中的DI(依赖注入)Dependence Import

由之前的IoC可以知道&#xff0c;我们写在具体对象后面的new方法肯定不能要了&#xff0c;这时候就要通过依赖注入的形式将Dao配置到Service中 Dependence Import的步骤如下&#xff1a; 1. 在Service类中给Dao提供setter方法 原本我们是直接给bookDao new了一个对象 public …

【Linux】vscode远程连接ubuntu失败

VSCode远程连接ubuntu服务器 这部分网上有很多&#xff0c;都烂大街了&#xff0c;自己搜吧。给个参考连接&#xff1a;VSCode远程连接ubuntu服务器 注意&#xff0c;这里我提前设置了免密登录。至于怎么设置远程免密登录&#xff0c;可以看其它帖子&#xff0c;比如这个。 …

vscode的git 工具使用

vscode的git 工具使用 目录概述需求&#xff1a; 设计思路实现思路分析1.git 工具的使用2.提交代码3.查看历史提交代码 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a be…