python运维自动化脚本案例,python自动化运维工具

python编写自动化运维工具,python自动化运维项目 众所周知,随着IT技术的进步以及业务需求的快速增长,每家企业内部都有许多的信息系统,如ERP、MES、OA、CRM等等,而每套系统又由许许多多的功能模块组成,如服务器、存储、数据库、备份系统、网络等等,这些节点也从几十台到成百上千台不等,并且各个系统之间又是紧密联系、互相影响,所以任何一个功能模块出现问题,都可能会影响到企业信息系统的正常运行,同样也会影响企业的高效运作,甚至会影响企业可持续发展。见微知著,格物致知。然而,我们都知道,其实真正厉害的人,是那些能够提前预判问题、解决问题并且避免事故发生的人。 阅读详情

大家好,给大家分享一下python自动化运维需要掌握的技能,很多人还不知道这一点。下面详细解释一下。现在让我们来看看!

本篇文章给大家谈谈python 运维开发都需要掌握哪些,以及python搭建自动化运维平台,希望对各位有所帮助,不要忘了收藏本站喔。

这两天在学校实训:用Python Django做学校的在线课堂系统,可谓是让我这个从未摸过Django和SQL的屌丝涨了市面快码知识python创意编程比赛作品。

工作之余,我无意之间翻了翻都写哪些经典的Python WEB框架:Flask、Django这些都太大了,自己手动写纯Socket工程量又太大......有没有什么好一点的这种方案呢?既可以实现轻量化,又可以不用去研究复杂的H5、JS和SQL```*``

最后还真的被我给找到了,这就是我们今天的主角:基于Python的MINI型APP框架:Streamlit高中信息技术python怎么学。

Streamlit原本的设计初衷是为了方便实现在WEB上搭建基于Python数据可视化或深度学习的APP以便于中小型团队能够快速的构建APP模型并针对APP中的BUG能够直观的查找并修正。

但是我就比较特立独行,你们既然都干这个,那我就干点花花的:用Streamlit搭建一个小型的运维监控平台。

其实我原来也曾试想着在Django的项目中嵌入一个Models去存储这些指标数据的,可是这么做的显然很不划算(只是我单纯的不想写模型罢了),于是乎借助Streamlit强大的API功能,我就开始了这个项目的构建。

环境准备

首先我们需要准备运行这个小APP的环境:

        -Anaconda3(别问我为什么不用原生Python,问就是懒得下包)

        -Streamlit:我们APP的主框架和逻辑支撑都靠它了

        -Pandas:用于存放短时数据流和部分数据表,之后会讲到

        -Psutil和Platform库:可以说没有这俩库这个APP写不成

        -Plotly:用于实现可视化效果(其实我只用了一个)

        -Pycuda:用于实现检测实例下的CUDA GPU数量极其部分属性

附上懒狗安包指令:

pip install streamlit psutil pandas pycuda plotly

准备好环境了,我们是时候开始写点东西了

主APP编写

在编写APP之前,我们需要认真的考虑下APP中UI的排版与布局,因为虽然Streamlit的API非常强大,但它提供的可选UI界面真的少的可怜,最后在我激烈的思想斗争之下,我选择了下拉菜单这种经典UI布局。

废话不多说,我上来就先构建了一个下拉菜单的实例:

#在这里使用set_page_config()方法定义APP在WEB浏览器上现实的标题和布局
st.set_page_config(page_title="Django实例--{}".format(platform.node()),
layout="wide")
#创建一个selectbox下拉菜单的实例,参数分别为盒子的名称以及其他监视对象的子菜单名称
sidebar = st.selectbox(
    "实例资源监视",
    ("基本信息","网络配置","基础监控","存储监控","弹性用户组配置","弹性安全组","GPU管理","命令终端")
)

好的,既然实例创建完成了,如何这个下拉菜单的实例动起来,或者随着我们点击不同业务单元,它就可以自动变换显示的内容,这是我们想要的结果。那么,这就需要对实例点击内容的判断了。

子APP编写

前面有提到过selectbox()方法下存放的两个参数:一个是盒子的名称,另外一个是由其他对象构成的数组,那么我们的逻辑一定是要从子对象的内容进行入手。

Streamlit的API在这一块就做的非常的贴心,你住需要一行简单到不能再简单的逻辑判断,即可实现对APP显示内容的变换。

if sidebar == "基本信息":
就这么简单!

知道怎么变化内容了,那现在就开始写些内容好咯:我的逻辑很简单,在基本信息中罗列了如下的信息:

#首先使用platform库下的system()方法获取到当前实例的运行系统内核
    system_kernel = platform.system()
    #写上标题,注意!:这个表题在前端显示的效果为H1,因此在落笔写标题的时候要慎重
    st.title("实例基本信息")
    #使用platform.node()方法获取当当前运行实例的名称
    st.write("设备名称:{}".format(platform.node()))
    # 需要申明:Linux端的返回数据和Windows端的并非相同,因此
    # 针对不同系统内核,你需要单独修改platform和psutil返回值
    # 的格式。本次APP将会以UBuntu系统下的情况为例。
    #检测到当前运行内核为Linux
    if system_kernel == "Linux":
        #使用platform.machine()方法,并截取字符串以获得到当前实例系统的运行位宽
        st.write("系统类型:{}{}位".format(system_kernel,platform.machine()[4:6]))
    #使用platform.platform()方法获取到当前实例下的系统版本
    st.write("系统版本:{}".format(platform.platform()))
    #psutil.cpu_count()方法返回当前实例的物理内核数量
    st.write("CPU:{}核".format(psutil.cpu_count()))
    #因为当前的实例是运行在虚拟机上的,因此
    #platform.processor()方法返回的是x86_64
    #而该方法在实体机下的返回值则是:Intel64 Family 6 Model 158 Stepping 10, GenuineIntel
    #可以看到在实体机下可以看到该实例下处理器的位宽,制造厂商,最大内核数以及步进(Stepping)
    st.write("CPU类型:{}".format(platform.processor()))
    #使用psutil.net_if_stats追踪到当前实例中连接到主网络的设备名称
    st.write("基础网路连接:{}".format(list(psutil.net_if_stats())[1]))
    #使用psutil.net_if_addrs()获取对应设备的IP
    st.write("IP:{}".format(list(psutil.net_if_addrs().values())[1][0][1]))
    #以上两个方法的返回值都是列表,因此与要进行切分

构建好基础信息之后我们需要开始构建网络配置下的内容了

#首先构建存放所有psutil模块下返回值的列表以供存储数据
    network_adpater_name = []
    network_adpater_isup = []
    network_adpater_workmode = []
    network_adpater_runspeed = []
    network_adpater_maximumtrans = []
    network_adpater_ip = []
    network_adpater_netmask = []
    #使用循环遍历出当前实例下所有的网络设备
    for i in range(len(list(psutil.net_if_addrs()))):
        network_adpater_name.append(list(psutil.net_if_addrs())[i])
        network_adpater_isup.append(list(psutil.net_if_stats().values())[i][0])
        #需要声明:psutil模块对应网卡工作模式的定义有些特殊,其返回值为整数数据
        #当返回值为2时,代表当前网络设备处于全双工的工作模式
        #当返回值为1时,代表当前网络设备处于半双工的工作模式
        network_adpater_workmode.append(list(psutil.net_if_stats().values())[i][1])
        network_adpater_runspeed.append(str(list(psutil.net_if_stats().values())[i][2])+"Mbps")
        network_adpater_maximumtrans.append(list(psutil.net_if_stats().values())[i][3])
        network_adpater_ip.append(list(psutil.net_if_addrs().values())[i][0][1])
        network_adpater_netmask.append(list(psutil.net_if_addrs().values())[i][0][2])
    #这里必须要用Pandas构建一个数据框,否则会很难看
    network_adpater_info = pd.DataFrame()
    network_adpater_info["网卡名称"] = network_adpater_name
    network_adpater_info["上行"] = network_adpater_isup
    network_adpater_info["工作模式"] = network_adpater_workmode
    network_adpater_info["运行速率"] = network_adpater_runspeed
    network_adpater_info["最大并行转发量"] = network_adpater_maximumtrans
    network_adpater_info["网卡IP"] = network_adpater_ip
    network_adpater_info["子网掩码"] = network_adpater_netmask
    st.title("当前Django实例网络配置信息")
    #使用StreamlitAPI下的table()方法将DataFrame数据框渲染出来
    st.table(network_adpater_info)

基础性能指标

通过对于基础性能指标参数的获取,这时我们需要引入流的概念。

通过上面对于参数获取并生成表,我们发现这种类型的数据是固定的,或者是对于动态的要求要求几乎微乎其微。

但是对于诸如:占用、速度这样矢量化数据而言。动态就显得尤为重要。

上代码:

#定义监视器函数并返回占用比
    def CPUMonitorWatchDog():
        usage = []
        while True:
            #在这里因为使用from pustil import *的引入方法
            #因此这里的cpu_percent不需要声明属于那个类下的
            #参数:interval=int用于设置psutil模块获取CPU占比的间隔
            #percpu:用于控制psutil模块在获取占用时是否将内核进行拆分
            usage.append(cpu_percent(interval=1, percpu=False))
            return usage
    def MemMonitorWatchDog():
        mem_usage = []
        while True:
            mem_usage.append(virtual_memory().percent)
            return mem_usage
    def readDiskWatchDog():
        read_speed = []
        while True:
            read_speed.append(psutil.disk_io_counters().read_bytes/1024/100)
            return read_speed
    def writeDiskWatchDog():
        write_speed = []
        while True:
            write_speed.append(disk_io_counters().write_bytes/1024/100)
            return write_speed
    def DownLoadNetMonitorWatchDog():
        download_speed = []
        while True:
            #这里net_ip_counters()中所有的返回值都是bit,因此无需转换为Byte
            #以保证
            first_recv = net_io_counters().bytes_recv
            sleep(1)
            second_recv = net_io_counters().bytes_recv
            download_speed.append((second_recv - first_recv))
            return download_speed
    def UPLoadNetMonitorWatchDog():
        upload_speed = []
        while True:
            first_sent = net_io_counters().bytes_sent
            sleep(1)
            second_sent = net_io_counters().bytes_sent
            upload_speed.append((second_sent - first_sent))
            return upload_speed
    def PackageSentMonitor():
        sent_pack = []
        while True:
            sent_pack.append(net_io_counters().packets_sent)
            return sent_pack
    def PackageReceiveMonitor():
        sent_pack = []
        while True:
            sent_pack.append(net_io_counters().packets_sent)
            return sent_pack
    #构建数据框以实时存储监视器们返回的数据
    df = pd.DataFrame(CPUMonitorWatchDog())
    #设置列长更新,以保证长度Y轴长度能够实时更新
    monitor_columns = [f"CPU占用率" for i in range(len(df.columns))]
    df.columns = monitor_columns  
    df["内存占用"] = MemMonitorWatchDog()
    df['读取速度'] = readDiskWatchDog()
    df["写入速度"] = writeDiskWatchDog()
    df["下载速度"] = DownLoadNetMonitorWatchDog()
    df["上传速度"] = UPLoadNetMonitorWatchDog()
    df["发包数量"] = PackageSentMonitor()
    df["接受包数量"] = PackageReceiveMonitor()
    #st.subheader()方法用于生成子标题,对应HTML中的h3标签
    first_header = st.subheader("CPU占用率")
    #使用st.area_chart()生成一个折线面积图的实例
    monitor_chart = st.area_chart(df[monitor_columns])
    second_header = st.subheader("内存占用率")
    mem_usage_charts= st.area_chart(df["内存占用"])
    third_header = st.subheader("磁盘读取速度(KB/s)")
    read_bytes_charts = st.area_chart(df["读取速度"])
    fourth_headers = st.subheader("磁盘写入速度(KB/s)")
    write_bytes_chart = st.area_chart(df['写入速度'])
    fivth_headers = st.subheader("下载速度(kb/s)")
    download_charts = st.area_chart(df["下载速度"])
    sixth_headers = st.subheader("上传速度(kb/s)")
    upload_charts = st.area_chart(df["上传速度"])
    seventh_headers = st.subheader("收包数量(个)")
    packrecv_charts = st.area_chart(df["接受包数量"])
    eighth_headers = st.subheader("发包数量")
    packsent_charts = st.area_chart(df["发包数量"])
    #开始进行数据迭代与填充
    while True:
        #因为每一个chart的类型属于DeletaGenerator对象,在Steamlit的API下
        #可以使用.add_rows()的方法拓宽数据,在参数中声明一个DataFrame和对应列以构建数据流
        monitor_chart.add_rows(pd.DataFrame(CPUMonitorWatchDog(), columns=monitor_columns))
        mem_usage_charts.add_rows(pd.DataFrame(MemMonitorWatchDog(),columns=["内存占用"]))
        read_bytes_charts.add_rows(pd.DataFrame(readDiskWatchDog(),columns=["读取速度"]))
        write_bytes_chart.add_rows(pd.DataFrame(writeDiskWatchDog(), columns=['写入速度']))
        download_charts.add_rows(pd.DataFrame(DownLoadNetMonitorWatchDog(),columns=["下载速度"]))
        upload_charts.add_rows(pd.DataFrame(UPLoadNetMonitorWatchDog(),columns=["上传速度"]))
        packrecv_charts.add_rows(pd.DataFrame(PackageReceiveMonitor(),columns=["接受包数量"]))
        packsent_charts.add_rows(pd.DataFrame(PackageSentMonitor(),columns=["发包数量"]))

构建完最复杂的动态可视化之后,我们尝试来构建存储方面监控与可视化

elif sidebar == "存储监控":
    #使用disk_usage()方法获取到指定盘符下的磁盘容量
    st.header("当前Django实例存储总量:{}".format(round(disk_usage("/").total/1024/1024/1000,2))+"GB")
    #使用disk_partitions()方法获取到当前实例下的所有分区
    st.header("共有{}个分区".format(len(psutil.disk_partitions())))
    total_partitions = []
    each_partion_usage = []
    #通过循环显示出实例下所有的分区,极其名称和占比
    #由于这个APP运行在了虚拟机上,而且虚拟磁盘是被拆分开来的,因此显示时只会获得所有虚拟分区
    for i in range(len(psutil.disk_partitions())):
        st.write("当前{}盘盘符占用:{}%,剩余{}GB".format(psutil.disk_partitions()[i].device,disk_usage(psutil.disk_partitions()[i].device).percent,round(disk_usage(psutil.disk_partitions()[i].device).free/1024/1024/1024),2)+"\n")
        total_partitions.append(psutil.disk_partitions()[i].device)
        each_partion_usage.append(disk_usage(psutil.disk_partitions()[i].device).percent)
    #创建一个plotly离线对象用于绘制分区占比
    pyplt = py.offline.plot
    labels = total_partitions
    values = each_partion_usage
    trace = [go.Pie(
    labels = labels, 
    values = values, 
    hole =  0.7,
    hoverinfo = "label + percent")]
    layout = go.Layout(
        title = "当前实例硬盘分区占比"
    )
    fig = go.Figure(data=trace,layout=layout)
    #调用streamlitAPI下的plotly_chart将之前plotly生成的figure写入到streamlit中
    st.plotly_chart(figure_or_data=fig,use_container_width=True)
    #捕获读写IOPs
    def readIOPsWatchDog():
        read_iops = []
        while True:
            read_iops.append(psutil.disk_io_counters().read_count)
            return read_iops
    def writeIPOsWatchDog():
        write_iops = []
        while True:
            write_iops.append(psutil.disk_io_counters().write_count)
            return write_iops
    df = pd.DataFrame(readIOPsWatchDog())
    readiops_columns = [f"顺序随机读取性能(IOPs)" for i in range(len(df.columns))]
    df.columns = readiops_columns 
    df["顺序随机写入性能(IOPs)"] = writeIPOsWatchDog()
    first_header = st.subheader("顺序随机读取性能(IOPs)")
    readiops_charts= st.area_chart(df["顺序随机读取性能(IOPs)"])
    second_header = st.subheader("顺序随机写入性能(IOPs)")
    writeiops_charts = st.area_chart(df["顺序随机写入性能(IOPs)"])
    while True:
        readiops_charts.add_rows(pd.DataFrame(readIOPsWatchDog(),columns=["顺序随机读取性能(IOPs)"]))
        writeiops_charts.add_rows(pd.DataFrame(writeIPOsWatchDog(),columns=["顺序随机写入性能(IOPs)"]))

接下来来到弹性用户组管理与配置

需要申明一点,这里为了方便查看用户组下的所有有效信息,建议在构建APP之前,记得给root配置免密登陆,否则每一次查看用户组时都需要切回Streamlit的控制台去输入root的密码,十分麻烦

#先检测一下系统内核
    system_kernel = platform.system()
    st.title("当前实例用户组配置信息")
    #这里设置一个用beta_columns()方法生成4个DeltaGenerator类的列对象
    col1,col2,col3,col4 = st.beta_columns(4)
    #针对每一个独立的列绑定一个按钮
    add_group_button = col1.button("添加用户组")
    delete_group_button = col2.button("删除用户组")
    add_user_button = col3.button("添加用户")
    delete_user_button = col4.button("删除用户")
    #当系统内核检测为Linux时则执行如下逻辑
    if system_kernel == "Linux":
        #读取/etc/group下的分组信息
        process = os.popen("sudo cat /etc/group").readlines()
        #创建四个列表用于存储分列数据
        group_name = []
        group_key = []
        gid = []
        user_list = []
        #开始分列
        for line in process:
            group_name.append(line.replace("\n","").split(":")[0])
            group_key.append(line.replace("\n","").split(":")[1])
            gid.append(line.replace("\n","").split(":")[2])
            user_list.append(line.replace("\n","").split(":")[3])
        #创建数据框
        df = pd.DataFrame()
        df["组名称"] = group_name
        df["组密钥"] = group_key
        df["GID"] = gid
        df["用户群"] = user_list
        st.table(df)
        #当按钮被按下时
        if add_group_button:
            #使用text_input()方法创建一个输入框用于记录添加的用户组名
            add_confirm = st.text_input("请输入你想添加的用户组")
            #当前长度不等于0时
            if len(add_confirm) != 0:
                #如果添加的
                if add_confirm.isin(df["组名称"]):
                    st.error("该用户组已存在,无法再次添加")
                else:
                    os.popen("sudo groupadd {}".format(add_confirm))
                    st.success("添加成功")
        if delete_group_button:
            delete_confirm = st.text_input("请确认你删除的用户组对象名称")
            if len(delete_confirm) != 0:
                #生成一个警告信息
                st.warning("该操作会影响实例系统下的用户组信息,请输入:我已知晓后果,并承担风险方可执行该操作!")
                #进行最终确认以防止误删
                final_confirm = st.text_input(label="最终确认")
                if final_confirm == "我已知晓后果,并承担风险方可执行该操作":
                    if delete_confirm in df["组名称"]:
                        os.popen("sudo groupdel {}".format(delete_confirm))
                        st.success("删除成功")
                    else:
                        st.error("请确认该用户组是否存在")
        if add_user_button:
            add_user_confirm = st.text_input("请输入你想添加的用户")
            if len(add_user_confirm) != 0:
                all_user = []
                for i in range(len(df["用户群"])):
                    single_group = df["用户群"][i].split(",")
                    for i in range(len(single_group)):
                        all_user.append(single_group[i])
                if add_user_confirm in all_user:
                    st.error("无法添加!目标用户已存在!")
                else:
                    os.popen("sduo adduser {}")
        if delete_user_button:
            delete_user_confirm = st.text_input("请输入你想删除的用户")
            if len(delete_user_confirm) != 0:
                st.warning("该操作会影响实例系统下的用户组信息,请输入:我已知晓后果,并承担风险方可执行该操作!")
                final_confirm = st.text_input(label="最终确认")
                if final_confirm == "我已知晓后果,并承担风险方可执行该操作":
                    if delete_user_confirm in all_user:
                        os.popen("sudo userdel --remove {}".format(delete_user_confirm))
                        st.success("删除成功")
                    else:
                        st.error("请确认该用户组是否存在")

配置弹性安全组选项

elif sidebar == "弹性安全组":
    #需额外声明,因终端输出值为一个极其不规则的值,因此无法实现十分规整的展示
    #因此如果想查看完整的安全组信息需要仍然在shell内执行
    with st.beta_expander("额外声明!"):
        st.write("如欲获得完整组策略信息,请使用命令终端或服务器Shell端进行查询")
    #设置两个分列
    col1,col2 = st.beta_columns(2)
    #绑定按钮
    add_rule_button = col1.button("添加规则")
    del_rule_button = col2.button("删除规则")
    if add_rule_button:
        col1.subheader("添加规则配置")
        rule_type = st.text_input("规则类型")
        port_rule = st.text_input("端口规则")
        add_button = st.button("确认添加")
        if add_button:
            os.popen("sudo ufw {} {}".format(rule_type,port_rule))
    if del_rule_button:
        col2.subheader("删除规则配置")
        port_rule = col2.text_input("端口规则")
        del_button = col2.button("确认删除")
        if del_button:
            os.popen("sudo ufw delete {}".format(port_rule))

前面有提到过我们导入了PyCuda包用于检测实例下存在的CUDA GPU数量和工作状态,那么我们开始最后一步:检测CUDA GPU

elif sidebar == "GPU管理":
    st.title("GPU技术由NVIDIA提供",st.image("https://developer.nvidia.com/sites/all/themes/devzone_new/favicon.ico"))
    #用pycuda.driver()方法初始化pycuda实例
    drv.init()
    #当driver检测设备时
    if drv.Device.count() != 0:
        #显示当前实例装载了多少个CUDA GPU
        st.header("当前实例装载了{}个CUDA GPU.".format(drv.Device.count()))
        #构建CUDA设备信息存放数据的列表
        cuda_device_name = []
        cuda_device_capability = []
        cuda_device_memory = []
        cuda_device_rundriver = []
        #循环输出CUDA信息并填充至之前构建的列表中
        for i in range(drv.Device.count()):
            device = drv.Device(i)
            cuda_device_name.append(device.name())
            cuda_device_capability.append(float("%d.%d" % device.compute_capability()))
            gpu_memory = device.total_memory()//(1024**2)//1024
            cuda_device_memory.append(gpu_memory)
            cuda_device_rundriver.append(drv.get_version()[0])
        #构建数据框
        df = pd.DataFrame()
        df["CUDA设备名称"] = cuda_device_name
        df["CUDA设备计算能力"] = cuda_device_capability
        df["CUDA设备内存"] = cuda_device_memory
        df["CUDA驱动版本"] = cuda_device_rundriver
        #使用table()方法显示出来
        st.table(df)
    else:
        st.error("当前Django服务器未装载GPU!")

好了,综上我们所有的功能都构建好了,之后就是启动我们的Streamlit APP了,启动方法也非常简单:使用cd命令切换到你的APP目录下,并输入

streamlit run xxx.py

即可顺利的运行啦,当然之前说streamlit的一大优势在于共享性,这也就意味着在你启动streamlit app时不仅有一个本地的localhost地址,同时也会有一个局域网地址。当你的服务器上顺利部署了streamlit的APP时,凡是与服务器处于同一局域网内的设备都可以访问到这个APP了。

最后如果喜欢本期分享的话,记得动动你可爱的小手,点赞、打赏、转发一键三联哦,我是Deaohst,我们下期分享见。

附上码云链接:https://gitee.com/P4r4I10w_W0nd3r/elins-code-storage/tree/myDjango/Streamlit

Python中的自动化运维和部署工具与技术 Python是一种非常适合自动化运维和部署的编程语言,因为它具有简单易学、功能强大、跨平台等特点。以下是一些在Python中常用的自动化运维和部署工具与技术,以及相关的代码示例。 阅读详情

相关推荐

基于FPGA与红外成像的眼动追踪系统设计与实现(教学向)

本文详细介绍了基于FPGA与红外成像的眼动追踪系统设计与实现。通过红外摄像头采集图像,利用FPGA进行实时图像处理和红外瞳孔追踪,结合Verilog编程实现多目标检测与瞳孔定位。该系统适用于嵌入式视觉教学,展示了硬件搭建、算法优化及实时显示的完整流程。

g5h6i7j的博客 823

Python 运维脚本整理归纳

Python 是一种功能强大且易于学习的编程语言,它在运维工程师的日常工作中扮演着重要的角色。Python 的简洁性和丰富的库生态系统使其成为编写自动化脚本和工具的理想选择。下面是一些运维工程师在日常工作中经常使用的 Python 脚本的概述。

微软技术分享 2万+

分辨率太小 / Retina 模糊 / 全屏异常:一篇解决 VMware Fusion + Kali 显示问题(Xfce & GNOME 通用)

本文提供了在Mac(尤其是Retina屏)上运行Kali Linux时常见显示问题的完整解决方案。主要解决三类问题:分辨率太小、Retina屏模糊和全屏异常。核心思路是先安装open-vm-tools-desktop并重启,这是90%问题的根源。然后根据不同问题分别处理:调整DPI/Scale解决字体大小,避免双重缩放导致的模糊,以及通过窗口拉伸和重启解决全屏异常。文章还给出了针对Xfce和GNOME的最佳配置建议,并强调调试完成后应创建快照以便快速恢复。最后提供了速查表,方便用户快速参考关键步骤。

致力于分享在各类技术领域的学习与实践经验,涵盖编程、虚拟化、开源工具、网络安全等。 874

5个常见运维场景,用这几个Python脚本就够了!

5个常见运维场景,用这几个Python脚本就够了!

一名正义的白帽黑客 986

安装破解IAR EWARM 8.2,提供注册机

IAR Embedded Workbench for ARM(IAR for ARM)是一款微处理器的集成开发环境软件,该集成开发环境中包含了IAR的C/C++编译器、 汇编工具、链接器、库管理器、文本编辑器、工程管理器和C-SPY调试器,支持ARM,AVR,MSP430等芯片。   一、安装 双击运行安装程序,点击Install IAR Embedded Workbench for ARM...

睿思派克 4万+

OrangePi Kunpeng Pro 安装 ROS2 + Gazebo

OrangePi Kunpeng Pro 的优点很明显,内置openEuler,配备PD电源,做到开箱即用;板子设计也不错,风扇噪音不大,散热良好,昇腾芯片又确保小板子的性能,接口丰富是这类板子共同的优点,也很好的继承了下来,甚至还可以外接固态,可靠性大大提升。使用起来,哪怕不用openEuler的话,也可以很方便的刷Ubuntu来实现一些需要依赖的开发工作,这次没有跑AI模型,所以对算力的优势还没有很明显的感受,下次可以试一下yolo跑跑看。

Arcan 1824

Python自动化运维实战:使用Python管理网络设备

Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。(全套教程文末领取哈)

m0_59235699的博客 5589

区块链入门:用账本、乐高和三台旧电脑讲懂分布式账本

区块链是一种去中心化的分布式账本技术,其核心原理是通过密码学哈希、共识机制和链式结构实现数据不可篡改与多方共同验证。它不依赖单一中心,而是将交易记录同步复制到多个节点,依靠数学规则而非人工信任达成一致,从而在数字世界构建可验证的信用基础设施。这种‘集体见证’模式显著提升了系统抗单点故障与人为干预的能力,广泛应用于供应链溯源、数字身份、教育管理及公益透明等需强信任保障的场景。本文以账本类比、乐高拆解和Ganache实操为线索,面向零基础读者通俗解析哈希值、挖矿与智能合约等关键概念。

weixin_30517215的博客 274

【Linux】Linux 下 Python 自动化:从脚本编写到运维工具开发(附案例)

在 Linux 运维场景中,重复性工作(如日志清理、服务监控、批量部署)占据了运维人员大量时间,而 Python 凭借其简洁的语法、丰富的内置库与第三方生态,成为 Linux 自动化运维的首选语言。相较于 Shell 脚本,Python 具备更强的逻辑处理能力、跨平台兼容性和可维护性,能轻松应对复杂的自动化需求;同时,Python 与 Linux 系统底层交互顺畅,可直接调用系统命令、操作文件目录、管理进程服务,大幅提升运维效率。

lbbxmx111的博客 1594

gdb对dwarf调试信息的解析和使用

gdb的对dwarf的调试信息的解析到使用的过程分析

JS072110的专栏 9568

QT/C++实现健壮HTTP POST客户端:从基础到异常处理与性能优化

HTTP协议作为客户端与服务器通信的基石,其POST方法在数据提交、API交互等场景中扮演着核心角色。其工作原理基于请求-响应模型,通过封装TCP连接与协议细节,为应用层提供了简洁的数据传输接口。在C++桌面与嵌入式开发中,直接使用底层Socket实现HTTP不仅复杂且易出错,而利用框架进行高级封装能显著提升开发效率与代码健壮性。QT框架的`QNetworkAccessManager`等组件正是为此设计,它通过信号槽机制提供异步网络编程模型,有效管理连接与协议解析。一个健壮的HTTP客户端需要妥善处理网络波

weixin_29176179的博客 384
上一篇: Python编程代码区alt放大,Python编程代码如何循环
下一篇: python自动化办公视频教程,python自动化办公源代码
普通网友
博客等级 码龄22年 1万+粉丝 3156原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值