zoukankan      html  css  js  c++  java
  • 老男孩Day3作业:练习文件操作(更新ha_proxy程序)

    作业要求

    1、实现针对ha_proxy文件的增删查改操作


     1)编写思路

    编写思路参考下面GitHub链接中的流程图

    https://github.com/ChuixinZeng/PythonStudyCode/blob/master/PythonCode-OldBoy/Day3/作业/Day3练习文件操作流程图.png


     2)具体实现

    # -*- coding:utf-8 -*-
    
    # Author:Chuixin Zeng
    
    # 导入正则表达式、时间日期模块
    import re,datetime
    
    # 定义ha_config变量,内容是ha_config.conf文件
    ha_config = "ha_config.conf"
    # 定义时间日期变量,供后面备份文件时使用
    bk_flag = datetime.datetime.now().strftime("%Y%H%M%S")
    
    # 定义update_file函数,该函数包含两个参数f1和f2,用于更新文件内容
    # 作用:用于删除backend,原理是,如果在ha_config中匹配到要删除的backend文件的话,不处理,不匹配的内容全部写入到ha_config.bk
    # 这样结束循环后,把ha_config.bk的内容写回到ha_config,那些匹配的内容自然就删掉了。。。
    def update_file(f1,f2):
        # 以写方式打开文件f1,以读方式打开文件f2
        # 下面这种with as写法的好处是不需要再使用close关闭文件了
        # f代表f1,f_old代表f2
        # 目的是把f2的内容更新到f1中
        with open(f1,"w") as f,open(f2,"r") as f_old:
            f.write(f_old.read())
            # flush操作执行后,才会把数据真正写入到f1对应的文件里面
            f.flush()
    
    # 定义一个backup_file的函数,该函数包含一个参数f,用于将原始文件备份
    def backup_file(f):
        # 定义f_bk变量,用于写打开.bk备份文件,文件名由f参数指定的名称+bk_flag定义的时间组成
        f_bk = open("%s_%s.bk" %(f,bk_flag),"w")
        # 这里f的文件名实际上原始文件和备份文件是一样的,只不过备份文件名多了一个日期
        # 所以,备份文件名是f+bk_flag,而原始文件名是f
        with open(f,"r",encoding="utf-8") as f:
            # 将原始文件内容备份到bk备份文件中
            f_bk.write(f.read())
            f_bk.flush()
    
    # 定义update函数,进行haconfig.conf文件的更新
    def update(args):
        if args:
            # 调用backup_file函数,针对原始的ha_config进行备份,备份完成的文件名是带日期的
            backup_file(ha_config)
            # 备份完成后,再执行下面的update操作
            # 以读打开ha_config文件,以写模式打开ha_config.bak文件,如果没有就新建
            with open(ha_config,"r") as f,open("%s.bk"% ha_config,"w") as f_new:
                # 从原始的ha_config文件循环读取内容,按行读取
                for line in f:
                    # 利用正则表达式匹配每一行,如果能匹配用户输入的server info中的backend和record的话执行if进行更新
                    # 不匹配的每一行都执行else
                    if re.match(args["backend"],line):
                        # 更新backend行的值
                        f_new.write(line)
                        # 更新record行的值,	是制表符
                        f_new.write("	%s" % args["record"])
                        line = f.readline() # 继续读取下一行,直到循环结束
                    else:
                        # 如果正则表达式没有匹配到backend字典的值,则将ha_config的值逐行写入到ha_config.bk中
                        f_new.write(line)
            # ,最终update完成的信息会放在bk文件里,然后调用更新文件的函数,将更新完成的ha_config.bk文件内容写回到ha_config
            update_file(ha_config,"%s.bk" % ha_config)
    
    # 定义一个函数,用于往ha_config文件里面新增backend内容
    def add_new_backend(args):
        if args:
            # 操作前先备份文件,备份完成的文件名是带日期的
            backup_file(ha_config)
            # 利用追加模式打开ha_config文件,也就是说文件如果不存在则创建;存在则只追加内容
            fp = open(ha_config,"a")
            # 追加的内容就是backend和record的值
            fp.write("
    %s
    	%s" % (args["backend"],args["record"]))
            # 最佳写入完成后,关闭文件
            fp.close()
    
    # 定义一个函数,用户判断特定backend和record的值是不是存在
    def config_diff(backend,record):
        # 2代表backend和record都已存在,1代表backend已存在,但是record值不一样,0代表backend不存在
        # 以读模式打开ha_config文件
        fp =open(ha_config,"r")
        # 设置result的值为0
        result = 0
        # 从ha_config文件里面读取内容
        for line in fp:
            # 如果读到了包含backend的行
            if re.match(backend,line):
                # 则返回值1
                result = 1
                # 继续读取下一行
                line = fp.readline()
                # 如果读到了包含record的行
                if re.match(".*%s" % record,line):
                    #则告诉用户已经发现匹配的文件
                    print("The backend config is found!")
                    # 返回值为2
                    result = 2
                    # 中断循环
                    break
        return result # 函数的返回值为result的具体值
    
    # 定义一个函数,用于添加或者更新ha_config.conf中的backend
    def add(args):
        # backend_info的值来源于函数convert_dict_to_conf,这个函数是把字典的值转换成配置文件
        backend_info = convert_dict_to_conf(args)
        if backend_info:
            # 调用config_diff函数,将backend_info中的值和ha_config中的值进行对比,以方便判断是否要添加新的backend或者更新backend
            diff = config_diff(backend_info["backend"],backend_info["record"])
            # 如果config_diff函数的返回值是2,则代表已经存在backend下面的record的值
            if diff == 2:
                print("The backend is already exists!")
            # 如果config_diff的函数的返回值是1,则代表匹配backend行的值,但是不匹配record的值,代表record的值有更新
            # 这种情况下就不是添加新的backend,而是更新现有的backend信息
            elif diff == 1:
                update(backend_info)
            # 如果以上条件都不满足,代表需要往ha_config中增加内容
            else:
                # 调用add_new_backend函数,增加新的内容
                add_new_backend(backend_info)
        else:
            return 0
    
    # 定义一个函数,用于删除ha_config中的backend行
    def delete_backend(args):
        if args:
            # 操作之前先备份
            backup_file(ha_config)
            # 以读模式打开ha_config,以写模式打开ha_config.bk
            with open(ha_config,"r") as f,open("%s.bk" % ha_config,"w") as f_new:
                # 循环遍历ha_config中的每一行
                for line in f:
                    # 如果有匹配backend的行
                    if re.match(args["backend"],line):
                        # 将读取到的值放到Line中
                        line = f.readline()
                    else:
                        #如果没有匹配到,则更新ha_config.bk文件
                        f_new.write(line)
            # 调用update_file函数,将ha_config.bk文件更新到ha_config,这样就达到了删除匹配的行的目的
            update_file(ha_config,"%s.bk" % ha_config)
    
    # 定义一个函数,用于删除backend
    def delete(args):
        backend_info = convert_dict_to_conf(args)
        # 调用config_diff函数,将backend_info中的值和ha_config中的值进行对比,以方便判断要删除的值是否在ha_config.conf中
        if backend_info:
            diff = config_diff(backend_info["backend"],backend_info["record"])
            # 如果函数返回值是2,代表存在要删除的值
            if diff ==2:
                # 调用delete_backend进行删除操作
                delete_backend(backend_info)
            else:
                # 如果对比后,要删除的值不存在,则告诉用户值不存在
                print("not found")
                print(backend_info["backend"],backend_info["record"])
        else:
            return 0
    
    # 定义一个函数search,用于查询用户输入的值是否存在
    def search(args):
        # 以读方式打开ha_config文件
        fp = open(ha_config,"r")
        for line in fp:
            # 如果匹配到了用户输入的内容
            if re.match("backend %s" % args.strip(), line):
                # 则打印该行
                print(line.strip())
                # 读取下一行,即backend包含的record是什么
                print(fp.readline())
                break
        else:
            # 如果没有匹配的内容,则输入下面的信息
            print("not found '%s' in config file" % args.strip())
    
    # 定义一个函数convert_to_dict,将用户输入的字符串类型转换成字典类型
    def convert_to_dict(args):
        # 通过使用eval函数,可以把list,tuple,dict和string相互转化
        args = eval(args)
        # 如果args的内容是字典类型,则返回args
        if type(args) == type({}):
            return args
        else:
            # 如果不是字典类型,则返回空数组
            return ""
    
    # 定义函数convert_dict_to_conf,用于将字典的内容转换成配置文件的格式
    def convert_dict_to_conf(args):
        # 将字典转换成配置文件所使用的格式
        # 判断convert_to_dict函数的返回值args里面的keys是否包含backend和record
        if "backend" in args.keys() and "record" in args.keys():
            # 如果存在,则将backend和record的key对应的value转换为下面的格式
            backend = "backend %s" % (args["backend"].strip())
            record = "server %s weight %s maxconn %s" % (args['record']["server"],
                                                         args['record']["weight"], args['record']["maxconn"],)
            # 函数返回转换后的格式
            return {"backend":backend,"record":record}
        else:
            # 如果匹配键key失败,则输出错误信息
            print("格式错误,key:record 或者record错误")
    
    
    def get_input_info():
        # 打印server info文字信息
        print("server info:")
        # 定义一个空字符串,用于保存用户输入的server info信息,即backend信息
        str_t = ""
        # iter函数,迭代器用起来很灵巧,你可以迭代不是序列但表现处序列行为的对象,例如字典的键、一个文件的行,等等
        for line in iter(input,""):
            # 将iter函数中用户输入的backend信息循环添加并追加到str_t变量中
            str_t += line
        # 将str_t变量的字符串值通过函数convert_to_dict转换为字典
        args = convert_to_dict(str_t)
        # 函数返回字典args的值,即server info下面用户输入的值
        if args:
            return args
        else:
            print("格式错误")
    
    while True:
        # 交互式提示用户要做哪方面的查询
        choose = input("what are you want to do?(add/delete/search/q):")
        # 如果用户输入了search
        if choose == "search":
            # 则进一步提示用户输入要查询的backendname,并告诉用户输入的格式
            args = input("输入backend 域名进行查找(如:www.oldboy.org):")
            # 如果输入的信息正确
            if args:
                # 则调用search函数,进行查找,输出用户查找的内容
                search(args)
            # 如果输入的信息不正确,提示格式错误
            else:
                print("格式错误")
        # 如果用户输入的是q。则退出程序
        elif choose == "q":
            break
        # 如果用户输入的是add
        elif choose == "add":
            print(input("请输入完整的backend和record信息进行添加或者在域名和IP不变的情况下,输入新的weight和maxconn值进行更新,格式如下:
    "
                        "请按键盘enter键继续,在server info中输入完整的新的backend信息...."))
            # 则调用get_input_info函数,提示用户输入要添加的server info信息,并把添加的信息放到args中
            args = get_input_info()
            # 如果用户输入的信息没问题,则调用add函数,将用户提供的信息添加到ha_config文件中
            if args:
                add(args)
        # 如果用户输入的是delete
        elif choose == "delete":
            # 则调用get_input_info函数,提示用户输入要添加的server info信息,并把添加的信息放到args中
            args = get_input_info()
            # 如果用户输入的信息没问题,则调用delete函数,将用户提供的信息添加到ha_config文件中
            if args:
                delete(args)

     3)GitHub笔记

    第三天的笔记地址:

    https://github.com/ChuixinZeng/PythonStudyCode/tree/master/PythonCode-OldBoy/Day3/随堂练习

    第三天的作业地址:

    https://github.com/ChuixinZeng/PythonStudyCode/tree/master/PythonCode-OldBoy/Day3/作业


     4)Readme文档

    https://github.com/ChuixinZeng/PythonStudyCode/blob/master/PythonCode-OldBoy/Day3/作业/Day3_练习文件操作.md

  • 相关阅读:
    SQLite剖析之功能特性
    SQLite剖析之内核研究
    SQLite剖析之体系结构
    SQLite安装、编译与应用
    实验四 数据库查询--2
    Linux监控一之Nagios的安装与配置
    keepalived原理(主从配置+haproxy)及配置文件详解
    负载均衡之Haproxy配置详解(及httpd配置)
    使用HeartBeat实现高可用HA的配置过程详解
    在Linux安装配置Tomcat 并部署web应用 ( 三种方式 )
  • 原文地址:https://www.cnblogs.com/ChuixinZeng/p/Jamie_Zeng_Day3.html
Copyright © 2011-2022 走看看