精华内容
下载资源
问答
  • 又是arp攻击 可恶,没事,用这款软件 反聚生网管,反网络执行官
  • 网络执法

    2011-01-08 01:16:05
    网络执法
  • python pymssql - pymssql模块官方文档的翻译

    千次阅读 多人点赞 2018-09-28 12:45:22
    此为pymssql模块version2.1.4官方文档的翻译,仅供学习交流使用,请勿用于商业用途。

    译者注:译者博客(http://blog.csdn.net/lin_strong),转载请保留这条。此为pymssql模块version2.1.4官方文档的翻译,仅供学习交流使用,请勿用于商业用途。

    模块级符号

    pymssql. version
    Unicode常量表示的pymssql版本。如:u"2.1.1", u"2.2.0"
    pymssql.VERSION
    元组形式的pymssql版本,这样在程序中更容易处理(转换、比较)。如:(2, 1, 1), (2, 2, 0)
    这是版本 2.2.0. 中新加的特性。
    pymssql. full_version
    Unicode常量表示的pymssql版本,不同的是,它包括了后缀(PEP 440)。如:u"2.1.0.dev2", u"2.2.0.dev"

    以下是DB-API 2.0规范中要求的常量:

    pymssql.apilevel
    ‘2.0’ – pymssql 尽可能地遵从 DB-API 2.0.
    pymssql.paramstyle
    ‘pyformat’ – pymssql 使用扩展的python格式代码.
    pymssql.threadsafety
    1 – 线程可以共享模块, 但不能共享连接。

    函数

    pymssql.connect(server=’.’, user=None, password=None, database=’’, timeout=0, login_timeout=60, charset=‘UTF-8’, as_dict=False, host=’’, appname=None, port=‘1433’, conn_properties=None, autocommit=False, tds_version=None)
    一个构造器(Constructor),用于创建到数据库的链接。返回一个Connection对象。

    注意:大部分情况下你应该会更倾向于使用关键字参数,而不是位置确定的参数。

    参数说明:

    参数名(类型)说明
    server (str)数据库主机
    user (str)用于连接的数据库用户
    password (str)用户的密码
    database (str)链接初始化的数据库。默认情况下,SQL服务器会选择设置中特定用户所对应的默认数据库。
    timeout (int)用秒表示的查询超时时间,默认为0(无超时)
    login_timeout (int)用秒表示的连接与登陆超时时间,默认为60
    charset (str)连接到数据库所使用的字符集
    as_dict (bool)是否每一行作为字典而不是元组返回。你可以使用基于0的索引或者使用名字来访问列。
    host (str)你想要连接的数据库主机或实体。如:
    r’.\SQLEXPRESS’ –本地机器上的SQLEXPRESS实体(仅Windows)
    r’(local)\SQLEXPRESS’ – 同上(仅Windows)
    ‘SQLHOST’ – 默认端口上的默认实体(仅Windows)
    ‘SQLHOST’ – 在freetds.conf中设置的指定端口上的指定实体 (仅Linux/*nix)
    ‘SQLHOST,1433’ – 指定主机上的指定TCP端口
    ’SQLHOST:1433’ – 同上
    ’SQLHOST,5000’ – 如果你已经设置了一个实体在端口5000进行监听
    ’SQLHOST:5000’ – 同上
    ’.’ (本地主机)默认设置,如果没有指定host。
    appname (str)设置链接使用的应用名
    port (str)连接到服务器所使用的TCP端口号
    conn_properties当链接建立时发送给服务器的SQLqueries。可以是一个字符串或者另一类可迭代的字符串组。默认值:见_mssql.connect()
    autocommit (bool)是否使用默认自动提交模式
    tds_version (str)使用的TDS协议版本
    警告:
    目前,设置timeout或login_timeout会有一个过程级的影响,因为用于实现超时的FreeTDS db-lib API函数是全局效果的。

    版本2.1.1中新特性: 能连接Azure。
    版本2.1.1中新特性: conn_properties参数。
    版本2.1.1中新特性: autocommit参数。
    版本2.1.2中新特性: tds_version参数。
    版本2.2.0的变化: 参数tds_version的默认值变为了None。在版本2.1.2中,其默认值为’7.1’。

    警告:
    参数tds_version的默认值为None。这意味着:
    你不能依赖于旧的默认值’7.1’。现在,你得做以下其中一件事:
    · 通过传递值给这个参数直接指定它的值,或者
    · 使用FreeTDS提供的方法配置它
    可能这看起来很麻烦,但同时意味着你可以在Python代码中完整地配置链接的特性,而不用再管freetds.conf了。在版本2.1.1及之前版本,没法控制TDS协议版本;在版本2.1.2中,可以设置它。如果没有指定的话,则使用版本7.1。
    警告:
    FreeTDS在版本0.95中添加了对TDS协议版本7.3的支持。如果你知道由pymssql使用的底层FreeTDS的版本是0.91的话,要小心不要要求TDS7.3,因为这即不会引发任何错误也没有机制阻止你传递这个无效值。
    警告:
    FreeTDS在版本0.95中添加了对TDS协议版本7.3的支持。如果你知道由pymssql使用的底层FreeTDS的版本更旧的话,要小心不要要求TDS7.3,因为这即不会引发任何错误也没有机制阻止你传递这个无效值。

    pymssql.get_dbversion()
    封装了DB库的dbversion()函数,这个函数会以字符串形式返回FreeTDS的版本(DB-Lib的实际版本)。如:“freetds v0.95”。
    不幸的是:
    1 )返回的值没有说明更小的修订号(如:v0.95.50)
    2 )它的数据类型使得它难以比较或编程处理
    3 )在FreeTDS发行历史中,它并没有被坚持更新
    这是pymssql对于DB-API 2.0的扩展
    pymssql.set_max_connections(number)
    设置允许同时连接到数据库的链接的最大数量。默认是25。
    这是pymssql对于DB-API 2.0的扩展
    pymssql.get_max_connections()
    获取允许同时连接到数据库的链接的最大数量。
    这是pymssql对于DB-API 2.0的扩展

    pymssql.set_wait_callback(wait_callback_callable)
    版本2.1.0. 中的新特性

    这个特性使得pymssql能用于协作的多任务系统,使其在等待服务器响应时调用一个回调函数。

    传递的可调用的回调函数应该接受一个参数:连接到服务器的网络socket的文件描述符/handle,所以其签名应该是这样的

    def wait_callback_callable(read_fileno):
        #...
        pass
    

    它的代码体应该调用你所使用的多任务框架的适当API,以使得当socket中没有输入数据时,当前greenlet主动交出CPU时间。

    这是pymssql对于DB-API 2.0的扩展

    Connection类

    class pymssql.Connection(user, password, host, database, timeout, login_timeout, charset, as_dict)
    这个类代表了一条MS SQL 数据库链接。你可以通过调用构建器pymssql.connect()来创建这个类的一个实例。

    属性

    这个类没有有用的属性和数据成员。

    方法

    Connection.autocommit(status)
    status是一个boolean值。这个方法返回autocommit模式是否启用
    默认的,autocommit模式是关闭的,这意味着如果要在数据库中保存变化的数据,必须明确地提交每个会话。
    你可以启用autocommit模式,这样,每个操作一旦成功就会提交自身。
    这是pymssql对于DB-API 2.0的扩展
    Connection.close()
    关闭链接。
    Connection.cursor()
    返回一个Cursor对象,这可以用于发送请求并从数据库获取结果。
    Connection.commit()
    提交当前会话。你必须调用这个方法来保存你的数据,如果autocommit为默认的False。
    Connection.rollback()
    回滚当前会话。

    Cursor类

    class pymssql.Cursor
    这个类代表一个Cursor(Python DB-API规范的术语),其用于向数据库发送请求并获取结果。通过调用一个打开的Connection链接对象的cursor()方法来创建Cursor实例。

    属性

    Cursor.rowcount
    返回上一次操作中受影响的行数。对于SELECT语句,只有在所有行都被fetched后它才会返回有用的信息。
    Cursor.connection
    这是对于DB-API规范的扩展。返回对创建cursor的Connection对象的引用。
    Cursor.lastrowid
    这是对于DB-API规范的扩展。返回上一个插入的行的标识值。如果之前的操作没涉及向带有标识列的表中插入行,则返回None。
    Cursor.rownumber
    这是对于DB-API规范的扩展。返回在当前结果集中,基于0的当前索引值。

    方法

    Cursor.close()
    关闭cursor。之后这个cursor就不可用了。
    Cursor.execute(operation)
    Cursor.execute(operation, params)
    operation是一个字符串;而params,如果用到了的话,是一个简单的值、元组、字典或None。
    对数据库执行operation,可能会用给的值替换占位符。比起手动连接字符串,这应该是更受欢迎的创建SQL命令的方法,手动连接字符串有受到SQL注入式攻击的风险。这个方法的格式化方式接近于Python内建的方式。但是,由于格式化和类型转换是内部进行的,只支持%s和%d占位符。这两个占位符在功能上与Python内建的是一样的。
    如果你给params传递的是字典的话,则支持关键字占位符。
    如果你调用了只带一个参数的execute(),%符号就丧失了它的特殊意义,这样你就可以如平常一样在查询字符串中使用它,比如用在LIKE操作符中。
    在调用execute()后,你必须调用Connection.commit(),否则数据不会被存到数据库中。如果你想要自动完成这件事的话,你也可以设置connection.autocommit。这个行为是DB-API要求的,如果你不喜欢的话,那就改用_mssql模块吧。
    Cursor.executemany(operation, params_seq)
    operation是一个字符串;而params_seq是一个元组的序列(比如一个列表)。为参数序列中的每一个元素重复执行operation这一数据库操作。
    Cursor.fetchone()
    获取查询结果的下一行,返回一个元组,或者如果as_dict为True的话返回一个字典。如果没有更多可获取的数据了,返回None。如果前一个对execute*() 的调用没有产生任何结果集或者还没有提交调用,则抛出OperationalError (PEP 249#operationalerror)。
    Cursor.fetchmany(size=None)
    获取下一批查询结果,返回一个元组的列表,或者如果as_dict为True的话返回一个字典。如果没有更多可获取的数据了,返回一个空列表。你可以使用size参数调整之后每一批获取的行数,这个值会一直保留使用。如果前一个对execute*() 的调用没有产生任何结果集或者还没有提交调用,则抛出OperationalError (PEP 249#operationalerror)。
    Cursor.fetchall()
    获取查询结果的所有剩余行,返回一个元组的列表,或者如果as_dict为True的话返回一个字典。如果没有更多可获取的数据了,返回一个空列表。如果前一个对execute*() 的调用没有产生任何结果集或者还没有提交调用,则抛出OperationalError (PEP 249#operationalerror)。
    Cursor.nextset()
    这个方法使cursor跳到下一个可得的结果集,抛弃当前集的所有剩下的行。如果有下一个结果集的话,返回True,否则返回None。
    Cursor. iter()
    Cursor.next()
    这个方法实现了Python迭代器协议。很可能你不会直接,而是间接使用迭代器调用它。
    这是pymssql对于DB-API 2.0的扩展
    Cursor.setinputsizes()
    Cursor.setoutputsize()
    这两方法啥都不做,这是DB-API规范同意的。

    异常

    exception pymssql.StandardError
    异常继承树的根。
    exception pymssql.Warning
    在重要的警告时抛出,如当插入时发生数据截断。StandardError的子类。
    exception pymssql.Error
    其他所有错误异常的基类。你可以用它来通过一个except语句捕获所有错误。StandardError的子类。
    exception pymssql.InterfaceError
    当发生与数据库接口相关而不是数据库本身相关的错误时抛出。Error的子类。
    exception pymssql.DatabaseError
    当发生与数据库相关的错误时抛出。Error的子类。
    exception pymssql.DataError
    当发生与处理数据相关的错误时抛出,如除以0、数值超出范围等。DatabaseError的子类。
    exception pymssql.OperationalError
    当发生与数据库运作相关但不应该是由程序员操作导致的错误时抛出,如意外的连接中断、没有找到数据源名字,无法处理一个会话、处理过程中的内存分配错误等。DatabaseError的子类。
    exception pymssql.IntegrityError
    当数据库的关系完整性受到影响时抛出,如外键检查失败。DatabaseError的子类。
    exception pymssql.InternalError
    当数据库遇到内部错误时抛出,如cursor不再有效、会话不同步。DatabaseError的子类。
    exception pymssql.ProgrammingError
    当发送编程错误时抛出,如没有发现表或表已存在、SQL语法错误、指定了错误数量的参数等。DatabaseError的子类。
    exception pymssql.NotSupportedError
    当使用了数据库不支持的方法或数据库API,如在一个不支持会话或者会话已关闭的链接上要求rollback()。DatabaseError的子类。
    exception pymssql.ColumnsWithoutNamesError
    当打开链接时指定as_dict=True,然后调用 Cursor.execute() 时发现结果中没有列名时抛出。InterfaceError的子类。
    注意:
    ColumnsWithoutNamesError不是PEP-249授权的异常,而是一个pymssql扩展。
    展开全文
  • salt常用命令、模块执行

    万次阅读 2016-03-11 10:24:02
    salt 该命令执行salt的执行模块,通常在master端运行,也是我们最常用到的命令 salt [options] '' [arguments] 如: salt '*' test.ping salt-run 该命令执行runner(salt带的或者自定义的,runner以后会讲),...


    一、salt常用命令

    1. salt 该命令执行salt的执行模块,通常在master端运行,也是我们最常用到的命令

      salt [options] '<target>' <function> [arguments]
      
      如: salt '*' test.ping
    2. salt-run 该命令执行runner(salt带的或者自定义的,runner以后会讲),通常在master端执行,比如经常用到的manage

      salt-run [options] [runner.func]
      salt-run manage.status   ##查看所有minion状态
      salt-run manage.down     ##查看所有没在线minion
      salt-run manged.up       ##查看所有在线minion
    3. salt-key 密钥管理,通常在master端执行

      salt-key [options]
      salt-key -L              ##查看所有minion-key
      salt-key -a <key-name>   ##接受某个minion-key
      salt-key -d <key-name>   ##删除某个minion-key
      salt-key -A              ##接受所有的minion-key
      salt-key -D              ##删除所有的minion-key
    4. salt-call 该命令通常在minion上执行,minion自己执行可执行模块,不是通过master下发job

      salt-call [options] <function> [arguments]
      salt-call test.ping           ##自己执行test.ping命令
      salt-call cmd.run 'ifconfig'  ##自己执行cmd.run函数
    5. salt-cp 分发文件到minion上,不支持目录分发,通常在master运行

      salt-cp [options] '<target>' SOURCE DEST
      salt-cp '*' testfile.html /tmp
      salt-cp 'test*' index.html /tmp/a.html
    6. salt-ssh 0.17.1版本加入的salt-ssh

    7. salt-master master运行命令

      salt-master [options]
      salt-master            ##前台运行master
      salt-master -d         ##后台运行master
      salt-master -l debug   ##前台debug输出
    8. salt-minion minion运行命令

      salt-minion [options]
      salt-minion            ##前台运行
      salt-minion -d         ##后台运行
      salt-minion -l debug   ##前台debug输出
    9. salt-syndic syndic是salt的代理,以后会说到

    二、普通用户执行salt

    普通用户执行salt两种方案:1,salt ACL 2.salt external_auth

    1.ACL

    1) 设置master配置文件

        client_acl:
        monitor:
         - test*:
        - test.*
        dev:
         - service.*
        sa:
         - .*

    2) 重启Master

    service salt-master restart

    3) 目录和文件权限

    chmod +r /etc/salt/master
    chmod +x /var/run/salt
    chmod +x /var/cache/salt

    4) 测试

    # su - monitor
    # salt 'test*' test.ping
    # exit; su - sa
    # salt '*' test.ping
    # salt '*' cmd.run 'uptime'
    # exit;

    2.external_auth

    1) 修改master配置文件

     external_auth:

    pam: monitor: – ‘test‘: – test. sa: – .* – 2) 3)与ACL相同

    4) 测试

     # salt -a pam 'test*' test.ping    ##会提示输入账号密码,所以external_auth与当前用户无关
       username: monitor
           password:
     # su - monitor
     # salt -a pam '*' cmd.run 'uptime'
    username: sa
    password:

    5) 使用Token不必每次都输入账号密码,使用external_auth每次都是需要密码的,这样多麻烦,这里引入了Token,它会保存一串字符到在当前用户家目录下.salt_token中,在有效时间内使用external_auth是不需要输入密码的,默认时间12hour,可以通过master配置文件修改

     # salt -T -a pam '*' test.ping

    username: sa

    password:

    #salt -a pam '*' test.ping #不会提示输入密码了

    三、target

    指定你的命令或者模块应用哪写Minion上

    1.globbing 默认

    salt 'test*' test.ping

    2.RE 正则

    salt -E 'web1-(pro|devel)' test.ping

    3.List 列表

    salt -L '127.0.0.1, test*' test.ping

    4.grains

    salt -G 'os:CentOS' test.ping
    
    #查看所有grains键/值
    salt 'test*' grains.items
    #查看所有grains项
    salt 'test*' grains.ls
    查看某个grains的值
    salt 'test*' grains.item num_cpus

    在top file中匹配grains

    'node_type:web':
      - match: grain         #没有s
      - webserver

    top file中使用jinja模板

    {% set self = grains['node_type'] %}
        - match: grain
    - {{ self }}

    5.nodegroups 其实就是对Minion分组

    首先在master的配置文件中对其分组,推荐写到/etc/salt/master.d/中一个独立的配置文件中,比如nodegroup.conf

    vim /etc/salt/master.d/nodegroup.conf 
    #写到master中也是这个格式,master.d中*.conf是默认动态加载的
    nodegroups:
     test1: 'L@test1,test2 or test3*'
     test2: G@os:CenOS or test2'
    
    salt -N test1 test.ping                #-N指定groupname
    
    在top file中使用nodegroups
    
    'test1':
     - match: nodegroup                   ##意没s
     - webserver

    6.混合指定,就是将以上的混合起来用

     G Grains glob G@os:Ubuntu
     E PCRE Minion ID E@web\d+\.(dev|qa|prod)\.loc
     P Grains PCRE P@os:(RedHat|Fedora|CentOS)
     L List of minions L@minion1.example.com,minion3.domain.com or bl*.domain.com
     I Pillar glob I@pdata:foobar
     S Subnet/IP address S@192.168.1.0/24 or S@192.168.1.100
     R Range cluster R@%foo.bar
    
     salt -C 'G@os:CentOS and L@127.0.0.1,192.168.1.12' test.ping

    top file 指定:

    'webserver* and G:CentOS or L@127.0.0.1,test1':
       - match: compound
    - webserver

    7.一次在n个minion上执行

    -b n
    --batch-size n
    示例:
    salt '*' -b 5 test.ping 55个的ping

    四、远程批量执行

    格式:

    salt '<target>' <function> [argument]

    注: function是salt带的或自己写的可执行模块里面的function,自带的所有列表http://docs.saltstack.com/ref/modules/all/index.html?highlight=full%20list%20builtin 实例:

    salt '*' at.at 10.10am 'uptime'
    salt '*' test.ping

    五、多Master

    1.在另一台机器上安装salt-master

    yum -y install salt-master

    2.将原来master上的master密钥拷贝到新的master是一份

    scp /etc/salt/pki/master/master* newmaster:/etc/salt/pki/master/

    3.启动新的Master

    service salt-master start

    4.修改minion配置文件/etc/salt/minion设置两个master

     master:
       - master1
    - master2

    5.重启minion

    service salt-minion restart

    6.在新的master上接受所有key

    salt-key -L
    salt-key -A

    注意:

    1.2个master并不会共享Minion keys,一个master删除了一个key不会影响另一个

    2.不会自动同步File_roots,所以需要手动去维护,如果用git就没问题了

    3.不会自动同步Pillar_Roots,所以需要手工去维护,也可以用git

    4.Master的配置文件也是独立的


    六、pillar

    Pillar在salt中是非常重要的组成部分,利用它可以完成很强大的功能,它可以指定一些信息到指定的minion上,不像grains一样是分发到所有Minion上的,它保存的数据可以是动态的,Pillar以sls来写的,格式是键值对

    适用情景:

    1.比较敏感的数据,比如密码,key等

    2.特殊数据到特定Minion上

    3.动态的内容

    4.其他数据类型

    查看Minion的Pillar信息

    salt '*' pillar.items

    查看某个Pillar值

    salt '*' pillar.item <key>      #只能看到顶级的
    salt '*' pillar.get <key>:<key> #可以取到更小粒度的

    编写pillar数据

    1.指定pillar_roots,默认是/srv/pillar(可通过修改master配置文件修改),建立目录

    mkdir /srv/pillar
    cd /srv/pillar

    2.编辑一个pillar数据文件

    vim test1.sls
    name: 'salt'
     users:
       hadoop: 1000
    redhat: 2000
    ubuntu: 2001

    3.建立top file指定minion到pillar数据文件

     vim top.sls
     base:
       '*':
         - test1

    4.刷新Pillar数据

    salt '*' saltutil.refresh_pillar

    5.测试

    salt '*' pillar.get name
    salt '*' pillar.item name

    在state中通过jinja使用pillar数据

    vim /srv/salt/user.sls
     {% for user, uid in pillar.get(’users’, {}).items() %}  ##pillar.get('users',{})可用pillar['users']代替,前者在没有得到值的情况下,赋默认值
     {{user}}:
       user.present:
         - uid: {{uid}}
     {% endfor %}

    当然也可以不使用jinja模板

    vim /srv/salt/user2.sls
    {{ pillar.get('name','') }}:
     user.present:
       - uid: 2002

    通过jinja模板配合grains指定pillar数据

    /srv/pillar/pkg.sls
    
    pkgs:
     {% if grains[’os_family’] == RedHat %}
     apache: httpd
     vim: vim-enhanced
     {% elif grains[’os_family’] == Debian %}
     apache: apache2
     vim: vim
     {% elif grains[’os’] == Arch %}
     apache: apache
     vim: vim
     {% endif %}

    七、grains

    服务器的一些静态信息,这里强调的是静态,就是不会变的东西,比如说os是centos,如果不会变化,除非重新安装系统

    定义minion的grains可以写在/etc/salt/minion中格式如下

    grains:
     roles:
       - webserver
       - memcache
     deployment: datacenter4
     cabinet: 13
     cab_u: 14-15

    或者写在/etc/salt/grains中,格式如下

    roles:
     - webserver
     - memcache
    deployment: datacenter4
    cabinet: 13
    cab_u: 14-15

    也可以在master中编写grains的模块,同步到minion中,用Python来写很简单的

    1.在/srv/salt中建立_grains目录

    mkdir /srv/salt/_grains

    2.编写grains文件,需要返回一个字典

     vim test1.py
     def hello():                      ##函数名字无所谓,应该是所有函数都会运行
       agrain = {}
       agrain['hello'] = 'saltstack'
    return agrain                   ##返回这个字典

    3.同步到各个minion中去

    salt '*' saltutil.sync_grains
    salt '*' saltutil.sync_all
    salt '*' state.highstate

    4.验证

    salt '*' grains.item hello

    八、使用 salt state

    它的核心是写sls(SaLt State file)文件,sls文件默认格式是YAML格式(以后会支持XML),并默认使用jinja模板,YAML与XML类似,是一种简单的适合用来传输数据的格式,而jinja是根据django的模板语言发展而来的语言,简单并强大,支持for if 等循环判断。salt state主要用来描述系统,软性,服务,配置文件应该出于的状态,常常被称为配置管理!

    通常state,pillar,top file会用sls文件来编写。state文件默认是放在/srv/salt中,它与你的master配置文件中的file_roots设置有关

    示例: apache.sls文件内容 ##/srv/salt/apahce.sls,以后没有用绝对路径意思就是在/srv/salt下

    apache:            ##state ID,全文件唯一,如果模块没跟-name默认用的ID作为-name
     pkg:             ##模块
       - installed    ##函数
      #- name: apache ##函数参数,可以省略
     service:         ##模块
       - running      ##函数
      #- name: apache ##函数参数,这个是省略的,也可以写上
       - require:     ##依赖系统
         - pkg: apache  ##表示依赖id为apache的pkg状态

    下面来解释上面示例的意思:

    声明一个叫apache的状态id,该id可以随意,最好能表示一定意思

    pkg代表的是pkg模块

    installed是pkg模块下的一个函数,描述的是状态,该函数表示apache是否部署,返回值为True或者False,为真时,表示状态OK,否则会去满足该状态(下载安装apache),如果满足不了会提示error,在该模块上面省略了参数-name: apache,因为ID为apache,这些参数是模块函数需要的(可以去查看源码)

    service是指的service模块,这个模块下主要是描述service状态的函数,running状态函数表示apache在运行,省略-name不在表述,-require表示依赖系统,依赖系统是state system的重要组成部分,在该处描述了apache服务的运行需要依赖apache软件的部署,这里就要牵涉到sls文件的执行,sls文件在salt中执行时无序(如果没有指定顺序,后面会讲到order),假如先执行了service这个状态,它发现依赖pkg包的安装,会去先验证pkg的状态有没有满足,如果没有依赖关系的话,我们可以想象,如果没有安装apache,apache 的service肯定运行会失败的,我们来看看怎么执行这个sls文件:

    salt '*' state.sls apache   

    在命令行里这样执行就ok了,.sls不要写,如果在目录下,将目录与文件用’.’隔开,如: httpd/apache.sls –> httpd.apache

    或者

    salt '*' state.highstate 

    这需要我们配置top file执定哪个minion应用哪个状态文件

    top.sls内容

    base:
     '*':
       - apache

    下面我们继续看一些比较复杂的:

    ssh/init.sls文件内容

    openssh-client:
     pkg.installed
    /etc/ssh/ssh_config:
     file.managed:
       - user: root
    - group: root
    - mode 644
    - source: salt://ssh/ssh_config
    - require:
     - pkg: openssh-client

    ssh/server.sls文件内容

    include:
     - ssh
    
    openssh-server:
     pkg.installed
    
    sshd:
     service.running:
       - require:
     - pkg: openssh-client
     - pkg: openssh-server
     - file: /etc/ssh/banner
     - file: /etc/ssh/sshd_config
    
    /etc/ssh/sshd_config:
     file.managed:
       - user: root
    - group: root
    - mode: 644
    - source: salt://ssh/sshd_config
    - require:
     - pkg: openssh-server
    
    /etc/ssh/banner:
     file:
       - managed
    - user: root
    - group: root
    - mode: 644
    - source: salt://ssh/banner
    - require:
     - pkg: openssh-server

    ssh/init.sls,学过Python的都知道目录下面的init文件是特殊文件,它怎么特殊呢,它特殊在当我们应用目录时会应用该文件的内容,如我们执行 salt ‘*’ state.sls ssh时应用的就是init.sls文件,明白了吗?再看里面的内容,前两行我们已经看过了,是描述某个rpm包有没有安装的,第三行是ID,也可以用来表示-name,以省略-name,file.managed是file模块与函数managed的快捷写法,看server.sls下最后就知道了,managed它描述了某个文件的状态,后面跟的是managed的参数,user,group,mode你们一看就知道什么意思了,关于这个source是指从哪下载源文件,salt://ssh/sshd_config是指的从salt的文件服务器里面下载,salt文件服务器其实就是file_roots默认/srv/salt/明白了吗,所以salt://ssh/sshd_config指的就是 /srv/salt/ssh/sshd_config,出来用salt的文件服务器,也可以用http,ftp服务器。- require是依赖系统不表,以后会详细说它的。再往下是server.sls文件,include表示包含意思,就是把ssh/init.sls直接包含进来

    这时你会看到/srv/salt的目录树是:

    ssh/init.sls
    ssh/server.sls
    ssh/banner
    ssh/ssh_config
    ssh/sshd_config

    下面再来看一个官方样例:

    ssh/custom-server.sls 文件内容

    include:
     - ssh.server
    extend:
     /etc/ssh/banner:
       file:
     - source: salt://ssh/custom-banner

    python/mod_python.sls文件内容

    include:
     - apache
    
    extend:
     apache:
       service:
     - watch:
       - pkg: mod_python

    首先我们include的别的文件,但是里面的内容并不是全部符合我们的要求,这时我们就需要用extend来重写部分内容,特殊的是依赖关系都是追加。custom-server.sls文件意思是包含ssh/server.sls,扩展/etc/ssh/banner,重新其source而其它的如user,group等不变,与include一致。 mode_python.sls文件意思是把apache.sls包含进来,想apache-service是追加了依赖关系(watch也是依赖系统的函数).

    常用状态配置 salt-states-master.zip

    九、关于渲染器render system

    我们上面也提过salt默认的渲染器是yaml_jinja,salt处理我们的sls文件时,会先把文件用jinja2处理,然后传给ymal处理器在处理,然后生成的是salt需要的python数据类型。除了yaml_jinja还有yaml_mako,yaml_wempy,py,pydsl,我比较感兴趣的就是yaml_jinja,还有py,yaml_jinja是默认的,而py是用纯python来写的。下面来看个样例吧,

    apache/init.sls文件内容

    apache:
     pkg:installed:
       {% if grains['os'] == 'RedHat' %}
    - name: httpd
    {% endif %}
     service.running:
       {% if grains['os'] == 'Redhat' %}
    - name: httpd
    {% endif %}
    - watch:
     - pkg: apache

    这个样例很简单,就是加了个判断,如果Minion的grains的os是RedHat那么apache的包名是httpd,默认是apache,我们知道在别的Linux发行版上,如ubuntu,suse他们的apache的包名就是叫apache,而在redhat系上则叫httpd,所以才有了这个判断写法,下面的service也是如此。我们着重说语法,jinja中判断,循环等标签是放在{% %}中的,通常也会有结束标签{% end** %},而变量是放在 {{ }}中的,salt,grains,pillar是salt中jinja里面的三个特殊字典,salt是包含所有salt函数对象的字典,grains是包含minion上grains的字典,pillar是包含minion上pillar的字典。

    示例:for user/init.sls文件内容

    {% set users = ['jerry','tom','gaga'] %}
    {% for user in users %}
    {{ user }}:
     user.present:
       - shell: /bin/bash
       - home: /home/{{ user }}
    {% endfor %}

    示例;salt字典 user/init.sls文件内容

    {% if salt['cmd.run']('uname -i') == 'x86_64' %}
    hadoop:
     user.present:
       - shell: /bin/bash
       - home: /home/hadoop
    {% elif salt['cmd.run']('uname -i') == 'i386' %}
    openstack:
     user.present:
       - shell: /bin/bash
    - home: /home/openstack
    {% else %}
    django:
     user.present:
       - shell: /sbin/nologin
    {% endif %}

    py渲染器 说明:py渲染器是用纯python写的sls文件,它返回的数据与yaml_jinja经过jinja处理经过yaml处理后的数据类似 ,用其他渲染器需要在sls文件头行声明用的渲染器类型,#!py就是声明用的py渲染器,py中可用的变量有salt,grains,pillar,opts,env,sls,前三个分别对应jinja里的salt,grains,pillar,opts是minion的配置文件的字典,env对应的是环境如base,sls对应的是sls的文件名

    示例: user/init.sls

    #!py
    import os
    def run():
       '''add user hadoop'''
    platform = os.popen('uname -a').read().strip()
    if platform == 'x86_64':
       return {'hadoop': {'user': ['present',{'shell': '/bin/bash'}, {'home': '/home/hadoop'}]}}
    elif platform == 'i386':
           return {'openstack': {'user': ['present', {'shell': '/bin/bash'}, {'home': '/home/openstack'}]}}
    else:
       return {'django': {'user': ['present', {'shell': '/sbin/nologin'}]}}

    说明: 首行声明了使用py作为渲染器,导入了os模块,声明run函数,py渲染sls文件是从run函数开始的,其它的就是python的语法了,注意的是return的数据结构{ID: {module: [func, arg1,arg2,...,]}} 或 {ID: {module.func: [arg1,arg2,..,]}} 。表示的内容与“示例;salt字典”表达的相同

    十、state的执行顺序

    以前我们说过,state的执行时无序,那个无序是指执行我们写的那个sls是无序的,正是因为那个无序,salt保证每次执行的顺序是一样的,就加入了state order,在说它之前看看High Data(高级数据?)和Low Data(低级数据?),高级数据我理解的就是我们编写sls文件的数据,低级数据就是经过render和parser编译过的数据。

    查看highdata

    salt '*' state.show_highstate

    查看lowdata

    salt '*' state.show_lowstate

    通过查看lowdata我们发现里面有一个字段order,因为salt默认会自动设置order,从10000开始。可以通过设置master配置文件参数state_auto_order: False来关闭

    Order的设定:

    1.include 被include的文件Order靠前,先执行

    2.手动定义order字段,如

      apache:
        pkg:
      - installed
      - order: 1
     order的数字越小越先执行从1开始,-1是最后执行

    3.依赖关系系统

    十一、依赖关系系统requisite system

    前面我们已经用过了依赖关系系统,就是定义状态与状态之间的依赖关系的,经常遇到的依赖系统的函数有’require’和’watch’和它们的变种’require_in’,’watch_in’,require和watch有什么区别吗?

    1.不是所有的state都支持watch,比较常用的是service

    2.watch定义的依赖条件发生变化时会执行一些动作,如当配置文件改变时,service会重启

    示例: apache/init.sls文件内容

    /etc/httpd/httpd.conf:
     file:
       - managed
    - source: salt://httpd/httpd.conf
    httpd:
     pkg:
       - installed
     service:
       - running
       - require:
         - pkg: httpd
       - watch:
         - file: /etc/httpd/httpd.conf            ##当httpd.conf改变时,重启httpd服务

    require与require_in, watch与watch_in

    require,watch是指依赖,require_in,watch_in是指被依赖

    a reuire b 那么就是b require_in a

    a watch b 那么就是b watch_in a

    示例: apache/init.sls文件内容

    /etc/httpd/httpd.conf:
     file:
       - managed
    - source: salt://httpd/httpd.conf
    - watch_in:
     - service: httpd
    httpd:
     pkg:
       - installed
    - require_in:
     - service: httpd
     service:
       - running

    十二、salt state环境

    针对不用环境,应用不同的state的file,salt支持多环境,比如开发,测试,生产等环境,我们通过修改Master配置文件对不同的环境应用不同的目录!

    file_roots:
     base:
       - /srv/salt/prod   ##生产环境
     qa:
       - /srv/salt/qa     ##测试环境,如果没发现去prod里面找
    - /srv/salt/prod
     dev:
       - /srv/salt/dev    ##开发环境,如果找不到,先去qa里找,如果找不到再去prod里面找
    - /srv/salt/qa
    - /srv/salt/prod
    /srv/salt/prod/top.sls文件内容
    base:
     'web*prod*':
       - webserver.foobarcom
    qa:
     'web*qa*':
       - webserver.foobarcom
    dev:
     'web*dev':
       - webserver.foobarcom
       - 

    pillar的目录与file_roots无关,所以Pillar的目录默认还是/srv/salt,pillar只是Minion的一些信息,不会对系统有什么改变,所以不需要区分环境,通常base即可。

    /srv/pillar/top.sls文件内容

    base:
     'web*prod*':
       - webserver.prod
     'web*qa*':
       - webserver.qa
     'web*dev*':
       - webserver.dev

    /srv/pillar/webserver/prod.sls文件内容

    webserver_role: prod

    /srv/pillar/webserver/qa.sls文件内容

    webserver_role: qa

    /srv/pillar/webserver/dev文件内容

    webserver_root: dev

    最后sls文件/srv/salt/prod/webserver/foobarcom.sls(该文件会被所有环境访问到)的内容:

    {% if pillar.get('webserver_role', '') %}
    /var/www/foobarcom:
     file.recurse:
       - source: salt://webserver/src/foobarcom
    - env: {{ pillar['webserver_role'] }}
    - user: www
    - group: www
    - dir_mode: 755
    - file_mode: 644
    {% endif %}

    开发完成后,应用sls文件

    1.现在开发环境

    salt -I ‘webserver_role:dev’ state.sls webserver.foobarcom

    十三、salt schedule

    schedule是salt中的crontab,就是周期性执行一些函数,需要注意的是在minion上执行的函数是salt的可执行模块里的函数,在master上执行的是runner模块的函数,下面看看如何设置: master是修改master配置文件/etc/salt/master:

    schedule:
     overstate:                    ##这个是ID,可以随意起,全文件唯一
       function: state.over        ##对于master,function就是runner
       seconds: 35                 ##间隔秒数
       minutes: 30                 ##间隔分数
       hours: 3                    ##间隔小时数

    这时每隔3小时30分35秒,master就会运行一个state.over这个runner

    minion的schedule定义有两种方式

    1.通过修改minion的配置文件,这种方式需要修改所有Minion的配置文件略麻烦

    schedule:
     highstate:
       function: state.highstate
    seconds: 30
    minutes: 5
    hours: 1

    2.为Minion指定pillar

    /srv/pillar/schedule.sls文件内容

    schedule:
     highstate:
       function: state.highstate
    seconds: 30
    minutes: 5
    hours: 1

    通过top file指定到Minion

    /srv/pillar/top.sls文件内容

    base:
     *:
       - schedule

    十四、YAML语法风格

    1.空格和Tabs

    在YAML中不要使用Tab

    2.缩进

    YAML推荐缩进为2个空格,’:’,’-’后面缩进1个空格再写

    3.数字会解析成数字

    如mode: 0644会解析成mode: 644,可用’括住防止mode: ’0644′此情况

    4.YAML不允许双简写

    vim:

    pkg.installed   ##第一个简写,单一个简写没问题
    user.present    ##第二个简写,加上它是不支持的

    不要偷懒写成下面这样吧。

    vim: pkg:
    - installed user: – present – 5.YAML只支持ASCII

    其它字符集最好不要使用,如果非要使用用以下格式:

    • micro: ‘\u00b5′

    6.下划线_将会被删除

    date: 2013_05_13  --> date: 20130513

    通过’括住防止出现该问题

    date: '2013_05_13'  

    十五、salt事件系统与反应系统 event and reacter system

    我们知道Master与Minion是基于ZMQ通信的,他们通信我们看来是消息队列,对它们来说这些消息就是一些事件,什么事件应该做什么,是salt基本已经预设好了。我们学习它的事件系统来完成一些自定义的行为,后面的反应系统就是基于事件系统的。一条消息其实就是一个事件,事件通常是一个字典数据,这个字典数据通常包含tag,这个tag是用来区分用途过滤消息的,详见绿大-https://groups.google.com/forum/#!topic/saltstack-users-cn/wXVE4ydnnzc ,让我们来看看这些事件。

    捕捉事件(listen event)

    1.下载官方给的事件捕捉程序eventlisten

    https://github.com/saltstack/salt/blob/develop/tests/eventlisten.py 打开网址,复制下载,不要直接wget

    2.运行该程序

    Master: python2.6 eventlisten.py                         ##捕捉master端的event直接运行即可
    Minion: python2.6 eventlisten.py -n minion <minion-id>   ##捕捉minion端的需要额外参数,minion-id是该Minion的id

    发送事件(fire event)

    Master发给minion

    salt '*' event.fire "{'data': 'some message'}" "tag"     ##前面必须是字符串包住的字典,后面是tag,如果你的minion在监听event,你会看到这条event的

    Minion发给minion

    salt-call event.fire_master 'some message' 'tag'  ##前面数据类型没有要求,后面是tag,去master那看看收到了没有

    Minion发给自己

    salt-call event.fire "{'data': 'some message'}" 'tag' ##前面必须是字符串包住的字典,后面是tag

    用code来捕捉,并发送event

    捕捉事件 Master:

    # python2.6
    >>> import salt.utils.event
    >>> event = salt.utils.event.SaltEvent('master', '/var/run/salt/master')
    ##master表明是在master端监听,/var/run/salt/master是你master的sock_dir
    >>> data = event.get_event()
    >>> print(data)       ##查看内容
    >>> data = event.get_event(wait=10, tag='auth') ##wait是指timeout时间,默认5s,用tag来过滤事件,可省略
    >>> print(data)                
    >>> for data in event.iter_events(tag='auth'):  ##用迭代器一直查看事件
    >>>     print(data)
    Minion:
    #python2.6
    >>> import salt.utils.event
    >>> event = salt.utils.event.SaltEvent('minion', '/var/run/salt/minion',id='minion_id')
    ##minion代表是在minion端监听,/var/run/salt/minion是minion端的sock_dir,minion_id是该Minion的id
    >>> data = event.get_event()
    >>> print(data)
    >>> for data in event.iter_events(tag='auth'):  ##用迭代器一直查看事件
    >>>     print(data)

    —————–先这样吧 发送事件:

    Master:
    >>> import salt.utils.event
    >>> event = salt.utils.event.SaltEvent('master', '/var/run/salt/minion')
    >>> event.fire_event({'hello': 'world'}, 'hello')

    —————–先这样

    反应系统(reacter system)

    反应系统是基于事件系统的,它的作用是当master收到来自minion的特殊事件后就触发某些动作,比如minion上线后发送一个init事件,master收到后,对其应用init的状态文件,minion没有反应系统,事情就是这样的。

    配置reactor

    1.修改master配置文件或者在/etc/salt/master.d/中建立reactor.conf,内容

    reactor:
     - 'testtag':                    ##接收到的tag
       - /srv/reactor/start.sls
    - /srv/reactor/monitor.sls
     - 'test1*tag':                  ##接收到的tag,支持通配符
       - /srv/reactor/other.sls
    • 2.建立reactor响应sls文件

    /srv/reacter/start.sls文件内容

    {% if data['id'] == 'mysql1' %}
    delete_file:
     cmd.cmd.run:
       - tgt: 'G@os:CentOS'
    - expr_form: compound
    - arg:
     - rm -rf /tmp/*
    {% endif %}

    /srv/reactor/other.sls文件内容

    {% if data['data']['state'] == 'refresh' %}
    overstate_run:
     runner.state.over
    {% endif %}

    下面来解释一下这两个文件,reacter的sls文件是支持jinja的,所以第一行是通过jinja来判断,reacter的sls支持两个变量data和tag, data是接受事件的那个字典,tag就是事件的tag,所以第一行的判断就很好理解了,第二行是id,可以随意起,第三行是要运行的执行模块或者runner,如果是执行模块,以cmd.开始,如果是runner则以runner.开始,可执行模块执行需要target,所以- tat:后面跟的就是可执行模块的target,- expr_form指的target的匹配方式,- arg是只执行模块函数的参数,runner一般不需要这些。所以第一个示例相当于执行了salt -C 'G@mysql1' cmd.run 'rm -rf /tmp/*' 第二个相当于执行了 salt-run state.over

    十六、salt Mine

    salt的用的词都太高明,像Grains,Pillar,Mine真心没一个合适的词去翻译,Mine是做什么的呢?Mine的作用是在静态数据和动态数据建立起一座桥梁(官方文档如是说),Mine从minon收集数据然后发送给Master,并缓存在Master端,所有Minion都可以轻易的共享到,Master通常会维护比较新的数据,如果需要维护长期数据,就要考虑retruner或外部的工作缓存了。 mine的出现是用来解决一定问题的. 在Salt的网络体系中,各个minion是毫无关系,相互独立的. 但是在实际应用中,minion之间其实是有一定关联的,比如一台机器需要获取到另一台机器的一些信息或者执行一些命令. 后来Salt加入了peer系统(http://docs.saltstack.com/ref/peer.html)使其成为可能. 但是peer系统每次使用的时候都会重新执行一遍, 显然很多不常变化的信息重复执行效率较低,性能开销较大. 所以就有了后来的mine(peer和mine的关系是我杜撰出来的,如有雷同,纯属巧合). mine系统存储在master端, minion想获取的时候, 通过mine.get获取下就可以了,简单方便

    修改minion配置文件,配置Mine

    mine_functions:
     network.interfaces: []
     test.ping: []
     mine_interval: 1

    重启Minion,在master端测试

    salt '*' mine_get '*' network.interfaces
    salt '*' mine_get '*' test.ping
    salt 'test1' mine_get '*' test.ping    ##查看test1上能得到mine数据

    十七、salt ssh

    从0.17.0开始salt加入salt ssh,salt ssh不需要在客户端安装salt-minion包了,是通过ssh协议来完成运城命令执行,状态管理等任务的。它是作为master-minion形式的补充出现的,原理是有一个花名册的文件,里面记录了各个minion的信息,ip,账号,密码,等,需要远程执行命令时,直接通过ssh来执行,速度与master-minion形式慢很多。

    使用: 1.配置/etc/salt/roster格式如下

    test1:
     host: 192.168.1.133
     user: salt
     passwd: redhat
     sudo: True
     port: 22
     timeout: 5
    test2:
     host: 192.168.1.134
     user: root
     passwd: redhat
    test3:
     host: 192.168.1.135
     user: sa
     sudo: True

    说明: test1我们定义了所有常见的选项,test2我们用了超级用户,使用账号密码,test3我们使用普通用户,没有写密码,就是通过key来认证了,并且以sudo方式执行的,需要注意的是1.key认证用的是/etc/salt/pki/master/ssh/目录下的密钥。2.如果普通用户的话,需要有sudo权限,因为一些功能,包括test.ping都需要sudo权限。

    测试:

     salt-ssh '*' test.ping
     salt-ssh '*' -r 'ls /'   ##执行shell命令
     salt-ssh '*' cmd.run 'ls /' ##用模块来执行也是可以的
     salt-ssh '*' state.sls   ##执行状态,state.sls在0.71.0中还存在bug,0.72.0中已解决

    十八、Returners

    默认所有minion返回的值都会发送到master端,我们可以看到,returner就是让Minion把返回的值发给其它地方,如redis,MySQL,或者一个文本 下面我们来自定义一个returner:

    1.建立自定义returner

    mkdir -p /srv/salt/_returners;
    vim mysql.py  ##就用官方给的例子吧,修改其中mysql的Host,user和pass

    内容见https://github.com/saltstack/salt/blob/develop/salt/returners/mysql.py

    2.建立需要的数据库

    见https://github.com/saltstack/salt/blob/develop/salt/returners/mysql.py注释里的见表语句

    3.授权其他主机用户可写该表

    >grant all on salt.* to 'user_in_returner'@'%' identified by 'passwd_in_returner';

    4.同步

    salt '*' saltutil.sync_all      ##同步到minion上去

    5.测试

    salt '*' test.ping --return mysql    ##数据返回到mysql上去,打开mysql查看

    十九、扩展salt

    通过自定义各个模块来扩展salt,常见自定义模块有:

    1.可执行模块 Execution Modules

    如我们常用的cmd.run , test.ping这样的可执行模块

    2.Grains

    扩展grains,grains是一些静态信息,可能好多我们需要的没有,我们可以通过编写grains模块自定义grains

    3.状态模块 State Module

    如我们常用的pkg.install,file.managed

    4.Returners

    我们可以自定义returner,将返回的数据发送到其他存储,只要符合固定的格式就行了

    5.Runner

    Runner是在master端快速执行的模块,自定义很方便

    二十、自定义可执行模块

    所有可执行module见https://github.com/saltstack/salt/tree/develop/salt/modules,或http://docs.saltstack.com/ref/modules/all/index.html?highlight=full%20list%20builtin

    1.建立自定义模块目录,通常所有自定义模块放在该目录下

    mkdir /srv/salt/_modules

    2.编写模块

    vim test.py
    -*- coding: utf-8 -*-
    '''
    support for yum of RedHat family!
    '''
    def __virtual__():
       '''
       Only RedHat family os can use it.
       '''
       if __grains__.get('os_family', 'unkown') == 'RedHat':
           return 'yum'
       else:
           return False
    
    
    def install(rpm):
       cmd = 'yum -y install {0}'.format(rpm)
       ret = __salt__['cmd.run'](cmd)
       return ret

    说明:__virtual__函数通常用来匹配是否满足该模块的环境,如果满足return出来的字符串作为该模块的名字而不是文件名,如果return的是False代表的此模块无效,不能使用。在自定义模块中可以中__grains__是一个包含了minion 所有grains的字典,__pillar__是包含了所有Pillar的grains字典,__salt__是所有可执行函数对象的字典,通常最常使用的就是这三个变量了。再往下面是定义了函数install,在salt中一般不用’%s’ % var这种格式化形式,而是使用字符串的format方法,具体使用见百度。下面就是通过__salt__执行了cmd.run这个函数来运行yum命令,很简单吧,最后把结果返回回去。

    3.测试

    salt '*' yum.install ftp  ##查看返回值

    二十一、自定义grains

    自定义的grains也是由Python写成的,通常放在/srv/salt/_grains下,grains需要返回一个字典,__salt__,__grains__,__pillar__也是可以在grains中使用的。前面已经介绍过写简单自定义grains了,复杂就就参照https://github.com/saltstack/salt/blob/develop/salt/grains/core.py官方这个吧

    二十二、自定义returner

    前面已经看过官方的mysql的returner了,今天来说说自定义returner需要注意的,来个例子吧。 /srv/salt/_returners/file.py内容

    def __virtual__():
       return 'file'
    def returner(ret):
       '''
       Return information to /tmp/returns.txt.
       '''
       # open a file
       result_file = '/tmp/returns.txt'
       f = open(result_file, 'a+')
       f.write(str(ret))
       f.close()
    
    salt '*' saltutil.sync_all         ##同步模块
    salt '*' test.ping --return file   ##测试
    cat /tmp/returns.txt               ##在minion上查看
    
    {'jid': '20131227153001246117', 'return': True, 'retcode': 0, 'success': True, 'fun': 'test.ping', 'id': 'test1'}

    说明: 通过这个简单的例子我们了解返回的值是个字典,字典包括的项就是上面我们看到的,以后写其它returner时,也就是把这个字典的值写到不同的地方而已。这个returner的意思就是把返回的值写到各个minion的/tmp/returns.txt中。

    二十三、file state backup

    来例子看看吧。 /srv/salt/test.sls文件内容

    /tmp/test.txt:
     file.managed:
       - source: salt://test.txt
       - backup: minion

    其中多了一个参数backup,后面跟的值minion,意思是说这个文件在minion中备份一份,文件名带着时间戳,备份位置在/var/cache/salt/minion/file_backup

    执行并测试:

    salt '*' state.sls test    ##注,多修改几次test.txt,多运行几次该state
    salt '*' file.list_backups /tmp/test.txt ##这是会返回备份序号,时间,位置,大小

    回退 当文件改错后,我们可以用备份文件回退

    salt '*' file.restore_backup /tmp/test.txt 2   ##回退的文件,与想要回退的序列号

    删除 删除不需要的备份文件

    salt '*' file.delete_backup /tmp/test.txt 3

    二十四、应用实例

    saltstack 远程触发文件备份、回滚

    1、创建模块方法文件

    mkdir /srv/salt/_modules

    默认没有此文件,自己生成一个

    下面的py文件自己定义,下面是我写的两个方法:

    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    import sys,string,shutil
    import os,tarfile
    import datetime,time
    
    tn=datetime.datetime.today()
    time_now=tn.strftime("%Y-%m-%d")
    data_bak='/data/databak'
    data_tmp='/data/databak/tmp/%s' % time_now
    com_f="%s/%s" % (data_bak,time_now)
    if not os.path.exists(com_f):
         os.makedirs(com_f)
    
    def CpFile():
         id = sys.argv[1]
         dir = sys.argv[2]            #传入两个变量,任务自动生成的id与要替换的文件
         filename = '%s/%s.tar' % (com_f, id)
         mode = 'w:tar'
         os.chdir(data_bak)                                                                                                                                                
         w_file=open("/tmp/tmp.list",'w')      
         w_file.write(id+" "+dir)              #记录每次备份的id与相对应的备份目录或文件的路径
         w_file.close()
         file = tarfile.open( filename, mode )
         file.add( '/tmp/tmp.list' )
         file.add( dir )    
         file.close()
         return 'ok'       #测试过程,就先让返回ok吧,之后再做判断
    
    
    def RollBack():
         id = sys.argv[1]        #想要回滚到的版本id
         if not os.path.exists(data_tmp):
              os.makedirs(data_tmp)
         filename = '%s/%s.tar' % (com_f, id)
         tar = tarfile.open("%s" % filename)
         for b in tar:
              tar.extract(b,path="%s" % data_tmp)
         tar.close()
         for line in open('%s/tmp/tmp.list' % data_tmp):
              id = line.split(" ")[:1][0]
              dir = line.split(" ")[1:][0]       #读取备份时的路径
              backup_dir='%s/%s' % (data_tmp,dir)
              os.system('\cp -rp %s %s' % (backup_dir,dir))
              return 'ok'

    2、测试:

    master上同步方法脚本到节点

    salt '*' saltutil.sync_all

    然后先测试备份 方法
    saltstack
        salt ‘*’ cp_bakfile.CpFile 1234  /tmp/test    #id + 路径

    上节点服务器上查看,存在

    把/tmp/test下内容删除,测试回滚操作

    salt '*' cp_bakfile.RollBack 1234

    使用gitfs做fileserver

    用gitfs后,master会从git服务器取回文件缓存,minion不会直接联系git服务器 修改master配置文件/etc/salt/master(注:以后说master配置文件就是指该文件)

    fileserver_backend:
     - git
    gitfs_remotes:
     - git://github.com/saltstack/saltstack.git
     - git://github.com/example/test1.git      ##可以多个git
     - file:///root/td                         ##可以使用本地git

    需要:python的模块GitPython >= 0.3.0

    saltstack的目录结构

    .
    |-- bfile
    |-- edit
    |   `-- vim.sls
    `-- top.sls
    vim.sls
    
    /tmp/a.txt:
     file.managed:
       - source: salt://bfile
    ftp:
     pkg:
       - installed

    也可以使用git下的子目录作为文件服务器根目录

    gitfs_root: somefolder/otherfolder

    也可以混合使用git和本地磁盘作为文件服务器

    fileserver_backend:
     - roots
     - git
     - 

    使用ssh协议的GitFS,私钥为~/.ssh/id_rsa

    gitfs_remotes:
     - git+ssh://git@github.com/example/salt-states.git
    推荐阅读:



    展开全文
  • TensorFlow之神经网络layers模块详解

    千次阅读 2018-07-22 15:54:34
    tf.nn,tf.layers, tf.contrib概述: 我们在使用tensorflow时,会发现tf.nn,tf.layers,... 下面是对三个模块的简述: (1)tf.nn :提供神经网络相关操作的支持,包括卷积操作(conv)、池化操作(pooling)、归...

    tf.nn,tf.layers, tf.contrib概述:

    我们在使用tensorflow时,会发现tf.nn,tf.layers, tf.contrib模块有很多功能是重复的,尤其是卷积操作,在使用的时候,我们可以根据需要现在不同的模块。但有些时候可以一起混用。 下面是对三个模块的简述: (1)tf.nn :提供神经网络相关操作的支持,包括卷积操作(conv)、池化操作(pooling)、归一化、loss、分类操作、embedding、RNN、Evaluation。 (2)tf.layers:主要提供的高层的神经网络,主要和卷积相关的,个人感觉是对tf.nn的进一步封装,tf.nn会更底层一些。 (3)tf.contrib:tf.contrib.layers提供够将计算图中的 网络层、正则化、摘要操作、是构建计算图的高级操作,但是tf.contrib包含不稳定和实验代码,有可能以后API会改变。
    以上三个模块的封装程度是逐个递进的。

    tf.layers模块介绍:

    Layers模块属于TensorFlow的一个稳定的中层API,其源码位于tensorflow/python/layers/layers.py,其官方文档地址为https://www.tensorflow.org/api_docs/python/tf/layers ref1

    tf.layers这个中层API基本上可以算是tf.nn模块的抽象,可以极大地加快模型的构建速度。

    tf.layers里面有很多封装好的类和函数。

    tf.layers模块提供的API:

    • input(…): 用于实例化一个输入 Tensor,作为神经网络的输入。
    • average_pooling1d(…): 一维平均池化层
    • average_pooling2d(…): 二维平均池化层
    • average_pooling3d(…): 三维平均池化层
    • batch_normalization(…): 批量标准化层
    • conv1d(…): 一维卷积层
    • conv2d(…): 二维卷积层
    • conv2d_transpose(…): 二维反卷积层
    • conv3d(…): 三维卷积层
    • conv3d_transpose(…): 三维反卷积层
    • dense(…): 全连接层
    • dropout(…): Dropout层
    • flatten(…): Flatten层,即把一个 Tensor 展平
    • max_pooling1d(…): 一维最大池化层
    • max_pooling2d(…): 二维最大池化层
    • max_pooling3d(…): 三维最大池化层
    • separable_conv2d(…): 二维深度可分离卷积层
    1. input

    tf.layers.Input() 这个方法是用于输入数据的方法,其实类似于 tf.placeholder,相当于一个占位符的作用,当然也可以通过传入 tensor 参数来进行赋值。Input这个类在1.8里面去除掉了。只能用tf.placeholder了, 所以在新版本中使用tf.placeholder是最好的选择

    • 用法
    Input(
        shape=None,
        batch_size=None,
        name=None,
        dtype=tf.float32,
        sparse=False,
        tensor=None
    )
    • 参数说明如下:
      shape:可选,默认 None,是一个数字组成的元组或列表,但是这个 shape 比较特殊,它不包含 batch_size,比如传入的 shape 为 [32],那么它会将 shape 转化为 [?, 32],这里一定需要注意。
      batch_size:可选,默认 None,代表输入数据的 batch size,可以是数字或者 None。
      name:可选,默认 None,输入层的名称。
      dtype:可选,默认 tf.float32,元素的类型。
      sparse:可选,默认 False,指定是否以稀疏矩阵的形式来创建 placeholder。
      tensor:可选,默认 None,如果指定,那么创建的内容便不再是一个 placeholder,会用此 Tensor 初始化。
      返回值:
      返回一个包含历史 Meta Data 的 Tensor。
    • 实例:
    x = tf.layers.Input(shape=[32])
    print(x)
    y = tf.layers.dense(x, 16, activation=tf.nn.softmax)
    print(y)

    首先我们用 Input() 方法初始化了一个 placeholder,这时我们没有传入 tensor 参数,然后调用了 dense() 方法构建了一个全连接网络,激活函数使用 softmax,然后将二者输出,结果如下:

    Tensor("input_layer_1:0", shape=(?, 32), dtype=float32)
    Tensor("dense/Softmax:0", shape=(?, 16), dtype=float32)

    这时我们发现,shape 它给我们做了转化,本来是 [32],结果它给转化成了 [?, 32],即第一维代表 batch_size,所以我们需要注意,在调用此方法的时候不需要去关心 batch_size 这一维。

    如果我们在初始化的时候传入一个已有 Tensor,例如:

    data = tf.constant([1, 2, 3])
    x = tf.layers.Input(tensor=data)
    print(x)

    结果如下:

    Tensor("Const:0", shape=(3,), dtype=int32)

    可以看到它可以自动计算出其 shape 和 dtype。

    2. batch_normalization

    此方法是批量标准化的方法,经过处理之后可以加速训练速度,其定义在 tensorflow/python/layers/normalization.py,论文可以参考:http://arxiv.org/abs/1502.03167“Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift”。

    • 用法
    batch_normalization(
        inputs,
        axis=-1,
        momentum=0.99,
        epsilon=0.001,
        center=True,
        scale=True,
        beta_initializer=tf.zeros_initializer(),
        gamma_initializer=tf.ones_initializer(),
        moving_mean_initializer=tf.zeros_initializer(),
        moving_variance_initializer=tf.ones_initializer(),
        beta_regularizer=None,
        gamma_regularizer=None,
        beta_constraint=None,
        gamma_constraint=None,
        training=False,
        trainable=True,
        name=None,
        reuse=None,
        renorm=False,
        renorm_clipping=None,
        renorm_momentum=0.99,
        fused=None,
        virtual_batch_size=None,
        adjustment=None
    )
    • 参数说明如下:

      • inputs:必需,即输入数据。
      • axis:可选,默认 -1,即进行标注化操作时操作数据的哪个维度。
      • momentum:可选,默认 0.99,即动态均值的动量。
      • epsilon:可选,默认 0.01,大于0的小浮点数,用于防止除0错误。
      • center:可选,默认 True,若设为True,将会将 beta 作为偏置加上去,否则忽略参数 beta
      • scale:可选,默认 True,若设为True,则会乘以gamma,否则不使用- - gamma。当下一层是线性的时,可以设False,因为scaling的操作将被下一层执行。
      • beta_initializer:可选,默认 zeros_initializer,即 beta 权重的初始方法。
      • gamma_initializer:可选,默认 ones_initializer,即 gamma 的初始化方法。
      • moving_mean_initializer:可选,默认 zeros_initializer,即动态均值的初始化方法。
      • moving_variance_initializer:可选,默认 ones_initializer,即动态方差的初始化方法。
      • beta_regularizer: 可选,默认None,beta 的正则化方法。
      • gamma_regularizer: 可选,默认None,gamma 的正则化方法。
      • beta_constraint: 可选,默认None,加在 beta 上的约束项。
      • gamma_constraint: 可选,默认None,加在 gamma 上的约束项。
      • training:可选,默认 False,返回结果是 training 模式。
      • trainable:可选,默认为 True,布尔类型,如果为 True,则将变量添加 - GraphKeys.TRAINABLE_VARIABLES 中。
      • name:可选,默认 None,层名称。
      • reuse:可选,默认 None,根据层名判断是否重复利用。
      • renorm:可选,默认 False,是否要用 Batch Renormalization (https://arxiv.org/abs/1702.03275)
      • renorm_clipping:可选,默认 None,是否要用 rmax、rmin、dmax 来 scalar Tensor。
      • renorm_momentum,可选,默认 0.99,用来更新动态均值和标准差的 Momentum 值。
      • fused,可选,默认 None,是否使用一个更快的、融合的实现方法。
      • virtual_batch_size,可选,默认 None,是一个 int 数字,指定一个虚拟 batch size。
      • adjustment,可选,默认 None,对标准化后的结果进行适当调整的方法。

    最后的一些参数说明不够详尽,更详细的用法参考:https://www.tensorflow.org/api_docs/python/tf/layers/batch_normalization

    • 实例
      其用法很简单,在输入数据后面加一层 batch_normalization() 即可:
    x = tf.layers.Input(shape=[32])
    x = tf.layers.batch_normalization(x)
    y = tf.layers.dense(x, 20)
    3. dense

    dense,即全连接网络,layers 模块提供了一个 dense() 方法来实现此操作,定义在 tensorflow/python/layers/core.py 中,下面我们来说明一下它的用法。

    • 用法
    dense(
        inputs,
        units,
        activation=None,
        use_bias=True,
        kernel_initializer=None,
        bias_initializer=tf.zeros_initializer(),
        kernel_regularizer=None,
        bias_regularizer=None,
        activity_regularizer=None,
        kernel_constraint=None,
        bias_constraint=None,
        trainable=True,
        name=None,
        reuse=None
    )
    • 参数说明如下:

      • inputs:必需,即需要进行操作的输入数据。
      • units:必须,即神经元的数量。
      • activation:可选,默认为 None,如果为 None 则是线性激活。
      • use_bias:可选,默认为 True,是否使用偏置。
      • kernel_initializer:可选,默认为 None,即权重的初始化方法,如果为 None,则使用默认的 Xavier 初始化方法。
      • bias_initializer:可选,默认为零值初始化,即偏置的初始化方法。
      • kernel_regularizer:可选,默认为 None,施加在权重上的正则项。
      • bias_regularizer:可选,默认为 None,施加在偏置上的正则项。
      • activity_regularizer:可选,默认为 None,施加在输出上的正则项。
      • kernel_constraint,可选,默认为 None,施加在权重上的约束项。
      • bias_constraint,可选,默认为 None,施加在偏置上的约束项。
      • trainable:可选,默认为 True,布尔类型,如果为 True,则将变量添加到 GraphKeys.TRAINABLE_VARIABLES 中。
      • name:可选,默认为 None,卷积层的名称。
      • reuse:可选,默认为 None,布尔类型,如果为 True,那么如果 name 相同时,会重复利用。
    • 返回值:
      全连接网络处理后的 Tensor。

    • 实例:

    x = tf.layers.Input(shape=[32])
    print(x)
    y1 = tf.layers.dense(x, 16, activation=tf.nn.relu)
    print(y1)
    y2 = tf.layers.dense(y1, 5, activation=tf.nn.sigmoid)
    print(y2)

    首先我们用 Input 定义了 [?, 32] 的输入数据,然后经过第一层全连接网络,此时指定了神经元个数为 16,激活函数为 relu,接着输出结果经过第二层全连接网络,此时指定了神经元个数为 5,激活函数为 sigmoid,最后输出,结果如下:

    Tensor("input_layer_1:0", shape=(?, 32), dtype=float32)
    Tensor("dense/Relu:0", shape=(?, 16), dtype=float32)
    Tensor("dense_2/Sigmoid:0", shape=(?, 5), dtype=float32)

    可以看到输出结果的最后一维度就等于神经元的个数,这是非常容易理解的。

    4. convolution

    convolution,即卷积,这里提供了多个卷积方法,如 conv1d()、conv2d()、conv3d(),分别代表一维、二维、三维卷积,另外还有 conv2d_transpose()、conv3d_transpose(),分别代表二维和三维反卷积,还有 separable_conv2d() 方法代表二维深度可分离卷积。它们定义在 tensorflow/python/layers/convolutional.py 中,其用法都是类似的,在这里以 conv2d() 方法为例进行说明。

    • 用法:
    conv2d(
        inputs,
        filters,
        kernel_size,
        strides=(1, 1),
        padding='valid',
        data_format='channels_last',
        dilation_rate=(1, 1),
        activation=None,
        use_bias=True,
        kernel_initializer=None,
        bias_initializer=tf.zeros_initializer(),
        kernel_regularizer=None,
        bias_regularizer=None,
        activity_regularizer=None,
        kernel_constraint=None,
        bias_constraint=None,
        trainable=True,
        name=None,
        reuse=None
    )
    • 参数说明如下:

      • inputs:必需,即需要进行操作的输入数据。
      • filters:必需,是一个数字,代表了输出通道的个数,即 output_channels。
      • kernel_size:必需,卷积核大小,必须是一个数字(高和宽都是此数字)或者长度为 2 的列表(分别代表高、宽)。
      • strides:可选,默认为 (1, 1),卷积步长,必须是一个数字(高和宽都是此数字)或者长度为 2 的列表(分别代表高、宽)。
      • padding:可选,默认为 valid,padding 的模式,有 valid 和 same 两种,大小写不区分。
      • data_format:可选,默认 channels_last,分为 channels_last 和 channels_first 两种模式,代表了输入数据的维度类型,如果是 channels_last,那么输入数据的 shape 为 (batch, height, width, channels),如果是 channels_first,那么输入数据的 shape 为 (batch, channels, height, width)。
      • dilation_rate:可选,默认为 (1, 1),卷积的扩张率,如当扩张率为 2 时,卷积核内部就会有边距,3x3 的卷积核就会变成 5x5。
      • activation:可选,默认为 None,如果为 None 则是线性激活。
      • use_bias:可选,默认为 True,是否使用偏置。
      • kernel_initializer:可选,默认为 None,即权重的初始化方法,如果为 None,则使用默认的 Xavier 初始化方法。
      • bias_initializer:可选,默认为零值初始化,即偏置的初始化方法。
      • kernel_regularizer:可选,默认为 None,施加在权重上的正则项。
      • bias_regularizer:可选,默认为 None,施加在偏置上的正则项。
      • activity_regularizer:可选,默认为 None,施加在输出上的正则项。
      • kernel_constraint,可选,默认为 None,施加在权重上的约束项。
      • bias_constraint,可选,默认为 None,施加在偏置上的约束项。
      • trainable:可选,默认为 True,布尔类型,如果为 True,则将变量添加到 GraphKeys.TRAINABLE_VARIABLES 中。
      • name:可选,默认为 None,卷积层的名称。
      • reuse:可选,默认为 None,布尔类型,如果为 True,那么如果 name 相同时,会重复利用。
    • 返回值:
      卷积后的 Tensor。

    • 实例:

    x = tf.layers.Input(shape=[20, 20, 3])
    y = tf.layers.conv2d(x, filters=6, kernel_size=2, padding='same')
    print(y)

    这里我们首先声明了一个 [?, 20, 20, 3] 的输入 x,然后将其传给 conv2d() 方法,filters 设定为 6,即输出通道为 6,kernel_size 为 2,即卷积核大小为 2 x 2,padding 方式设置为 same,那么输出结果的宽高和原来一定是相同的,但是输出通道就变成了 6,结果如下:

    Tensor("conv2d/BiasAdd:0", shape=(?, 20, 20, 6), dtype=float32)

    但如果我们将 padding 方式不传入,使用默认的 valid 模式,代码改写如下:

    x = tf.layers.Input(shape=[20, 20, 3])
    y = tf.layers.conv2d(x, filters=6, kernel_size=2)
    print(y)

    结果如下:

    Tensor("conv2d/BiasAdd:0", shape=(?, 19, 19, 6), dtype=float32)

    结果就变成了 [?, 19, 19, 6],这是因为步长默认为 1,卷积核大小为 2 x 2,所以得到的结果的高宽即为 [(20 - 2)/1 + 1)] x [(20 - 2)/1 + 1] = 19 x 19。

    当然卷积核我们也可以变换大小,传入一个列表形式:

    x = tf.layers.Input(shape=[20, 20, 3])
    y = tf.layers.conv2d(x, filters=6, kernel_size=[2, 3])
    print(y)

    这时我们的卷积核大小变成了 2 x 3,即高为 2,宽为 3,结果就变成了 [?, 19, 18, 6],这是因为步长默认为 1,卷积核大小为 2 x 2,所以得到的结果的高宽即为 [(20 - 2)/1 + 1)] x (20 - 3)/1 + 1)] = 19 x 18。

    如果我们将步长也设置一下,也传入列表形式:

    x = tf.layers.Input(shape=[20, 20, 3])
    y = tf.layers.conv2d(x, filters=6, kernel_size=[2, 3], strides=[2, 2])
    print(y)

    这时卷积核大小变成了 2 x 3,步长变成了 2 x 2,所以结果的高宽为 [(20 - 2)/2 + 1)] x [(20 - 3)/2 + 1)] = 10 x 9,得到的结果即为 [?, 10, 9, 6]。

    另外我们还可以传入激活函数,或者禁用 bias 等操作,实例如下:

    x = tf.layers.Input(shape=[20, 20, 3])
    y = tf.layers.conv2d(x, filters=6, kernel_size=2, activation=tf.nn.relu, use_bias=False)
    print(y)

    这样我们就将激活函数改成了 relu,同时禁用了 bias,运行结果如下:

    Tensor("conv2d_5/Relu:0", shape=(?, 19, 19, 6), dtype=float32)

    另外还有反卷积操作,反卷积顾名思义即卷积的反向操作,即输入卷积的结果,得到卷积前的结果,其参数用法是完全一样的,例如:

    x = tf.layers.Input(shape=[20, 20, 3])
    y = tf.layers.conv2d_transpose(x, filters=6, kernel_size=2, strides=2)
    print(y)

    例如此处输入的图像高宽为 20 x 20,经过卷积核为 2,步长为 2 的反卷积处理,得到的结果高宽就变为了 40 x 40,结果如下:

    Tensor("conv2d_transpose/BiasAdd:0", shape=(?, 40, 40, 6), dtype=float32)
    5. pooling

    pooling,即池化,layers 模块提供了多个池化方法,这几个池化方法都是类似的,包括 max_pooling1d()、max_pooling2d()、max_pooling3d()、average_pooling1d()、average_pooling2d()、average_pooling3d(),分别代表一维二维三维最大和平均池化方法,它们都定义在 tensorflow/python/layers/pooling.py 中,这里以 max_pooling2d() 方法为例进行介绍。

    • 用法
    max_pooling2d(
        inputs,
        pool_size,
        strides,
        padding='valid',
        data_format='channels_last',
        name=None
    )
    • 参数说明如下:

      • inputs: 必需,即需要池化的输入对象,必须是 4 维的。
      • pool_size:必需,池化窗口大小,必须是一个数字(高和宽都是此数字)或者长度为 2 的列表(分别代表高、宽)。
      • strides:必需,池化步长,必须是一个数字(高和宽都是此数字)或者长度为 2 的列表(分别代表高、宽)。
      • padding:可选,默认 valid,padding 的方法,valid 或者 same,大小写不区分。
      • data_format:可选,默认 channels_last,分为 channels_last 和 channels_first 两种模式,代表了输入数据的维度类型,如果是 channels_last,那么输入数据的 shape 为 (batch, height, width, channels),如果是 channels_first,那么输入数据的 shape 为 (batch, channels, height, width)。
      • name:可选,默认 None,池化层的名称。
    • 返回值:
      经过池化处理后的 Tensor。

    • 实例

    x = tf.layers.Input(shape=[20, 20, 3])
    print(x)
    y = tf.layers.conv2d(x, filters=6, kernel_size=3, padding='same')
    print(y)
    p = tf.layers.max_pooling2d(y, pool_size=2, strides=2)
    print(p)

    在这里我们首先指定了输入 x,shape 为 [20, 20, 3],然后对其进行了卷积计算,然后池化,最后得到池化后的结果。结果如下:

    Tensor("input_layer_1:0", shape=(?, 20, 20, 3), dtype=float32)
    Tensor("conv2d/BiasAdd:0", shape=(?, 20, 20, 6), dtype=float32)
    Tensor("max_pooling2d/MaxPool:0", shape=(?, 10, 10, 6), dtype=float32)

    可以看到这里池化窗口用的是 2,步长也是 2,所以原本卷积后 shape 为 [?, 20, 20, 6] 的结果就变成了 [?, 10, 10, 6]。

    6. dropout

    dropout 是指在深度学习网络的训练过程中,对于神经网络单元,按照一定的概率将其暂时从网络中丢弃,可以用来防止过拟合,layers 模块中提供了 dropout() 方法来实现这一操作,定义在 tensorflow/python/layers/core.py。

    • 用法
    dropout(
        inputs,
        rate=0.5,
        noise_shape=None,
        seed=None,
        training=False,
        name=None
    )
    • 参数说明如下:

      • inputs:必须,即输入数据。
      • rate:可选,默认为 0.5,即 dropout rate,如设置为 0.1,则意味着会丢弃 10% 的神经元。
      • noise_shape:可选,默认为 None,int32 类型的一维 Tensor,它代表了 dropout mask 的 shape,dropout mask 会与 inputs 相乘对 inputs 做转换,例如 inputs 的 shape 为 (batch_size, timesteps, features),但我们想要 droput mask 在所有 timesteps 都是相同的,我们可以设置 noise_shape=[batch_size, 1, features]。
      • seed:可选,默认为 None,即产生随机熟的种子值。
      • training:可选,默认为 False,布尔类型,即代表了是否标志为 training 模式。
      • name:可选,默认为 None,dropout 层的名称。
    • 返回:
      经过 dropout 层之后的 Tensor。

    • 实例:

    x = tf.layers.Input(shape=[32])
    print(x)
    y = tf.layers.dense(x, 16, activation=tf.nn.softmax)
    print(y)
    d = tf.layers.dropout(y, rate=0.2)
    print(d)

    运行结果:

    Tensor("input_layer_1:0", shape=(?, 32), dtype=float32)
    Tensor("dense/Softmax:0", shape=(?, 16), dtype=float32)
    Tensor("dropout/Identity:0", shape=(?, 16), dtype=float32)

    在这里我们使用 dropout() 方法实现了 droput 操作,并制定 dropout rate 为 0.2,最后输出结果的 shape 和原来是一致的。

    7. flatten

    flatten() 方法可以对 Tensor 进行展平操作,定义在tensorflow/python/layers/core.py。

    flatten(
        inputs,
        name=None
    )
    • 参数说明如下:

      • inputs:必需,即输入数据。
      • name:可选,默认为 None,即该层的名称。
    • 返回结果:
      展平后的 Tensor。

    • 实例:

    x = tf.layers.Input(shape=[5, 6])
    print(x)
    y = tf.layers.flatten(x)
    print(y)

    运行结果:

    Tensor("input_layer_1:0", shape=(?, 5, 6), dtype=float32)
    Tensor("flatten/Reshape:0", shape=(?, 30), dtype=float32)

    这里输入数据的 shape 为 [?, 5, 6],经过 flatten 层之后,就会变成 [?, 30],即将除了第一维的数据维度相乘,对原 Tensor 进行展平。

    假如第一维是一个已知的数的话,它依然还是同样的处理,示例如下:

    x = tf.placeholder(shape=[5, 6, 2], dtype=tf.float32)
    print(x)
    y = tf.layers.flatten(x)
    print(y)

    结果如下:

    Tensor("Placeholder:0", shape=(5, 6, 2), dtype=float32)
    Tensor("flatten_2/Reshape:0", shape=(5, 12), dtype=float32)
    8. 类

    除了如上的方法,其实我们还可以直接使用类来进行操作,实际上看方法的实现就是实例化了其对应的类,下面我们首先说明一下有哪些类可以使用:

    • class AveragePooling1D: 一维平均池化层类
    • class AveragePooling2D: 二维平均池化层类
    • class AveragePooling3D: 三维平均池化层类
    • class BatchNormalization: 批量标准化层类
    • class Conv1D: 一维卷积层类
    • class Conv2D: 二维卷积层类
    • class Conv2DTranspose: 二维反卷积层类
    • class Conv3D: 三维卷积层类
    • class Conv3DTranspose: 三维反卷积层类
    • class Dense: 全连接层类
    • class Dropout: Dropout 层类
    • class Flatten: Flatten 层类
    • class InputSpec: Input 层类
    • class Layer: 基类、父类
    • class MaxPooling1D: 一维最大池化层类
    • class MaxPooling2D: 二维最大池化层类
    • class MaxPooling3D: 三维最大池化层类
    • class SeparableConv2D: 二维深度可分离卷积层类
      其实类这些类都和上文介绍的方法是一一对应的,关于它的用法我们可以在方法的源码实现里面找到,下面我们以 Dense 类的用法为例来说明一下这些类的具体调用方法:
    x = tf.layers.Input(shape=[32])
    dense = tf.layers.Dense(16, activation=tf.nn.relu)
    y = dense.apply(x)
    print(y)

    这里我们初始化了一个 Dense 类,它只接受一个必须参数,那就是 units,相比 dense() 方法来说它没有了 inputs,因此这个实例化的类和 inputs 是无关的,这样就相当于创建了一个 16 个神经元的全连接层。

    但创建了不调用是没有用的,我们要将这个层构建到网络之中,需要调用它的 apply() 方法,而 apply() 方法就接收 inputs 这个参数,返回计算结果,运行结果如下:

    Tensor("dense/Relu:0", shape=(?, 16), dtype=float32)

    因此我们可以发现,这些类在初始化的时候实际上是比其对应的方法少了 inputs 参数,其他的参数都是完全一致的,另外需要调用 apply() 方法才可以应用该层并将其构建到模型中。

    所以其他的类的用法在此就不一一赘述了,初始化的参数可以类比其对应的方法,实例化类之后,调用 apply() 方法,可以达到同样的构建模型的效果。

    展开全文
  • 远程执行命令 运维自动化平台不可避免地会涉及到远程命令执行操作,主要分为两类主要...使用ssh的模块居多,fabric和ansible是此类工具中的典型,这类工具的优点是方便,不用在目标机安装agent。值得一提的是,这两...

    远程执行命令

    运维自动化平台不可避免地会涉及到远程命令执行操作,主要分为两类主要做法:目标机器安装agent,或者使用ssh。

    saltstack是一个典型的agent模式的远程控制工具,麻烦的地方是首先要在目标机器上安装saltstack的agent。

    使用ssh的模块居多,fabric和ansible是此类工具中的典型,这类工具的优点是方便,不用在目标机安装agent。值得一提的是,这两个工具都是基于paramiko。

    使用ssh执行的另一种做法是,直接调用本地的ssh来完成。缺点是针对每一台远程主机都需要开一个进程,比起在程序内建立连接要耗费更多的资源。优点也很明显,比如,公司最近在做ssh的改造,在改造的过程中,可能会出现明明ssh命令可以连接,使用第三方模块就是不灵的情况。ssh的命令和第三方模块在配置上毕竟有差异,需要维护两份配置。

    这篇文章就是要使用进程来完成在批量远程机器上执行某个命令。

    subprocess模块大概

    subprocess模块是python2中的一个官方模块,顾名思义,它主要用于操作子进程。

    subprocess.Popen()用于创建一个子进程,它的第一个参数是列表,即创建进程所需要的参数,类似c语言中的argv。

    需要注意的一点是,Popen是异步执行的,也就是说创建Popen后会立刻返回,子进程继续执行。关于异步,还有很多可以聊的地方,后面另开一篇文章写一下。

    既然是异步的,我们就需要某种机制来跟它进行通信。Popen提供了多个方式来与子进程通信。

    Popen.wait()将主程序挂起等待子进程的结束,结束后会返回子进程的返回码。

    Popen.poll()可以检测子进程是否还在执行,并返回子进程的返回码。

    下面我们将用几个小例子来不断扩展,最终实现一个可在多台远程机器并行执行命令的功能。

    一个简单的远程执行示例

    我们来写一个简单的示例,说明如何使用subprocess模块远程执行一条命令。

    import subprocess
    
    
    cmd = 'echo hello'
    cmd_arg = ['ssh', 'localhost', cmd]
    
    process = subprocess.Popen(
        cmd_arg, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    retcode = process.wait()            # 0
    out = process.stdout.read()         # 'hello'
    err = process.stderr.read()         # ''

    我们首先创建了一个Popen对象,然后等待这个子进程的执行结束,获取返回值和输出。

    这断代码很简单,注意stdout=subprocess.PIPE,我们想捕捉到子进程的输出,而不是直接打印到标准标出,所以要求Popen把输出打印到管道供我们读取。

    同时在多个机器上执行命令

    这里我们利用了Popen的异步特性,来加快多服务器任务的执行。

    import subprocess
    
    
    cmd = 'sleep 3 && echo hello'
    cmd_arg1 = ['ssh', 'localhost', cmd]
    cmd_arg2 = ['ssh', '127.0.0.1', cmd]
    
    process1 = subprocess.Popen(
        cmd_arg1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    process2 = subprocess.Popen(
        cmd_arg2, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    
    retcode1 = process1.wait()
    retcode2 = process1.wait()

    这次,我们连接了两个机器并执行耗时3s的操作,由于Popen是异步的,这个脚本的实际执行时间仍然是3s。这个地方的操作是不是与多线程的操作有点类似,哈哈。

    多个机器执行获取执行时间

    由于网络环境和机器配置的不同,我们在不同机器的执行时间是有差别的。有时候,我们需要一个时间数据来了解哪个机器执行耗时比较久,以此做优化。

    这时,我们需要Popen.poll()来异步检测命令是否执行完成,而不是将主进程挂起等待第一个子进程。如果第一个子进程执行时间比第二个子进程要长,我们就获取不到第二个子进程的执行时间。

    为了更好的可读性,这里我们没有加入for循环之类的结束,放弃了部分逻辑上的灵活性。

    import time
    import subprocess
    
    
    cmd = 'sleep 3 && echo hello'
    cmd_arg1 = ['ssh', 'localhost', cmd]
    cmd_arg2 = ['ssh', '127.0.0.1', cmd]
    
    process1 = subprocess.Popen(
        cmd_arg1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    process2 = subprocess.Popen(
        cmd_arg2, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    
    process1_ok = False
    process2_ok = False
    
    start_time = time.time()
    while True:
        if process1_ok and process2_ok:
            break
    
        if not process1_ok:
            if process1.poll() is not None:
                process1_ok = True
                print 'process 1 finished, delta time:', time.time() - start_time
    
        if not process2_ok:
            if process2.poll() is not None:
                process2_ok = True
                print 'process 2 finished, delta time:', time.time() - start_time
    
        time.sleep(1)       # 防止空跑导致cpu占用过高

    执行输出为:

    process 1 finished, delta time: 4.01682209969
    process 2 finished, delta time: 4.01691508293

    最后的执行时间多了1s,这是因为我们做了一个time.sleep(1)操作。由于我们考查的是哪台机器影响了整体的耗时,而且远程任务执行时间远不止1s,所以这里的1s不影响我们的判断。当然,适当缩小time.sleep()的参数也是可以的。

    封闭一个可并行在多台服务器执行的函数

    我们将上面的脚本封闭一下,形成一个可以复用的函数。有点长,但是只是在之前基础上做了一些简单的操作,并没有增加什么高深的东西。

    def run(hostname, command, user=None):
        """
        使用ssh执行远程命令
    
        hostname    字符串或数组,多个hostname使用数组
        """
        if not isinstance(hostname, list):
            hostname = [hostname]
        else:
            hostname = list(set(hostname))
    
        # 创建执行命令子进程
        processes = {}
        for h in hostname:
            if user is None:
                user_at_hostname = h
            else:
                user_at_hostname = '{0}@{1}'.format(user, h)
    
            cmd_args = ['ssh', user_at_hostname, command]
            processes[h] = subprocess.Popen(
                cmd_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    
        # 等待子进程结束,获取结果
        start_time = time.time()
        result = {}
        while True:
            running_hostnames = set(processes.keys()) - set(result.keys())
            if len(running_hostnames) == 0:
                break
    
            for h in running_hostnames:
                process = processes[h]
                retcode = process.poll()
    
                if retcode is None:
                    continue
    
                status = STATUS_SUCC if retcode == 0 else STATUS_FAIL
                out, err = process.stdout.read(), process.stderr.read()
                delta_time = time.time() - start_time
    
                result[h] = {
                    'out': out,
                    'err': err,
                    'status': status,
                    'delta_time': delta_time
                }
    
            time.sleep(1)
    
        r = {
            'ts': time.time(),
            'cmd': command,
            'result': result,
        }
    
        return r
    展开全文
  • 这里就需要用到网络这块的知识,这一篇就来说下仿人人的网络模块是如何架构的,先来看下网络处理模块的类图:  一、网络请求基类(AsyncBaseRequest),是一个实现Runnable接口的线程类。  初始化时的...
  • 一个是视觉互动网络 VIN,能够预测视觉场景中各个物体在未来几百步所处位置,另一个则是模块化的、具有关系推理能力的深度神经网络架构 RN,可以“即插即用”,提升其他深度神经网络结构(如 CNN)关系推理的能力。...
  • WebKit模块化分析

    万次阅读 热门讨论 2013-01-03 22:51:17
    模块化  软件的首要技术使命是管理复杂度(Complexity)。这是>中的一个标题。软件本质性困难的根源都在于复杂性。Dijkstra指出没有谁的大脑能容得下一计算机程序。正如社会进步催生社会分工一样,软件行业也...
  • 一直想写一下我在React Native原生模块封装方面的一些经验和心得,来分享给大家,但实在抽不开身,今天看了一下日历发现马上就春节了,所以就赶在春节之前将这篇博文写好并发布。
  • 4G模块连接TCP

    万次阅读 2020-06-28 09:58:41
    Air724模组内置TCP/IP协议栈,提供TCP客户端和服务器端服务(PS:模块没有公网IP所以服务端模式多用于专属VPN网络)。可使用AT指令,LUAT二次开发,CSDK,开源DTU等多种方式开发,开发者根据实际需求合理选择开发...
  • python之pexpect模块

    千次阅读 多人点赞 2020-03-21 16:51:16
    python之pexpect模块一:pexpect简介二:基本使用流程三:API使用3.1 spawn类3.2 expect()方法3.3 sendline()方法3.4 其他发送信息的方法3.5 其他获取结果的方法四:应用案例五:SSH专用类 一:pexpect简介 以下演示...
  • CommonJS就是为JS的表现来制定规范,因为js没有模块的功能所以CommonJS应运而生,它希望js可以在任何地方运行,不只是浏览器中。 CommonJS能有一定的影响力,我觉得绝对离不开Node的人气,不过喔,Node,...
  • windows 上面python3.5.2安装一些模块

    千次阅读 2017-01-17 14:50:12
    安装环境安装numpy模块建议官网下载安装http://www.lfd.uci.edu/~gohlke/pythonlibs/(这个网址重要,包含很多需要的python库文件,),numpy是一个基础模块,很多模块依赖这个模块。下载文件后本地安装命令: pip ...
  • 渗透之——Metasploit命令及模块

    万次阅读 2019-01-26 10:26:29
    列出metasploit框架中的所有渗透攻击模块。 show payloads 列出metasploit框架中的所有攻击载荷。 show auxiliary 列出metasploit框架中的所有辅助攻击载荷。 search name 查找metasploit框架中所有的渗透攻击和其他...
  • Ansible5:常用模块

    千次阅读 2016-08-01 10:56:13
    根据zs官方的分类,将模块按功能分类为:云模块、命令模块、数据库模块、文件模块、资产模块、消息模块、监控模块网络模块、通知模块、包管理模块、源码控制模块、系统模块、单元模块、web设施模块、windows模块 ...
  • 4G模块连接MQTT

    万次阅读 2020-06-28 09:56:36
    Air724模块内置MQTT协议,提供AT,LUAT,CSDK,DTU可供选择使用,接口简单使用方便。 MQTT简介 优势:长连接,低带宽,高可靠。 实用场景:需要服务器下发消息给设备,需要及时收到。例如,远程开关,充电桩等 几...
  • Python中的urllib.request模块

    万次阅读 多人点赞 2016-08-25 18:08:02
    因为在玩Python challenge的时候,有用过这个模块,而且学习这个模块之后也对系统学习网络爬虫有用。当时查了各种资料学习,没有碰官网文档(因为还是对英语有抗拒性),但是还是官方的文档最具权威和学习价值,因此...
  • 这里我不会带着大家从Glide代码执行的第一步一行行重头去解析Glide的源码,而是只分析和自定义模块相关的部分。如果你想将Glide的源码通读一遍的话,可以去看本系列的第二篇文章 Android图片加载框架最全解析(二)...
  • Python开发安装的一些常用模块

    万次阅读 2015-05-31 00:12:20
    ===========================... 本文主要是博主自己看到的或者了解的,但更大一部分是博主要使用的一些python模块,如有错误,还望大家指正 windos下安装第三方模块时若出错请参考:http://blog.csdn.net/gamer_g...
  • ansible小结(七)常用模块

    千次阅读 2016-11-01 18:54:39
    根据官方的分类,将模块按功能分类为:云模块、命令模块、数据库模块、文件模块、资产模块、消息模块、监控模块网络模块、通知模块、包管理模块、源码控制模块、系统模块、单元模块、web设施模块、windows模块 ...
  • 本文将从实际项目中遇到的问题出发,讲述模块化能解决哪些问题,以及如何使用 Sea.js 进行前端的模块化开发。恼人的命名冲突我们从一个简单的习惯出发。我做项目时,常常会将一些通用的、底层的功能抽象出来,独立成...
  • nodemcu各个模块 以及中文说明

    千次阅读 2019-06-21 01:10:38
    来看一下每个模块都是干什么的: 官方固件下载: https://nodemcu-build.com/ (机翻简单校对, 有些模块我也不太懂) 中文说明 https://github.com/nodemcu/nodemcu-firmware/wiki/nodemcu_api_cn (转自...
  • WIFI模块ESP8266-01S

    千次阅读 2020-11-23 00:58:13
    1. 安信可公司物联网模块: ESP8266系列Wi-Fi模块一共有01~14十多款模块 2.ESP-01S尺寸、管脚定义 3.ESP-01S和ESP-01区别 ESP8266-01简称ESP-01, ESP8266-01S简称ESP-01S 3.1 外观区别: ESP8266-...
  • 我们想写一个逍遥模拟器的中控,一个逍遥模拟器中控加大漠多线程模板,离不开逍遥模拟器模块的封装,本套教程调用了官方的接口memuc和原生态的ADB来实现对模拟器的控制和读取。memuc是v6.0.0版本推出的命令行工具,...
  • ansible常用模块

    千次阅读 2016-12-26 17:30:55
    一、ping模块测试主机是否是通的,用法很简单,不涉及参数:[root@361way ~]# ansible 10.212.52.252 -m ping 10.212.52.252 | success >> { "changed": false, "ping": "pong" }二、setup模块setup模块,主要用于...
  • 通过上节的例子,我们发现Apache插件开发的一个门槛便是学习它自成体系的一套API。虽然Apache的官网上有对... 为了实现最基础的URL解析等功能,我把《Apache模块开发指南》一书粗略了翻看了两遍,以利于迅速了解Ap...
  • python模块大全

    万次阅读 多人点赞 2017-06-28 09:46:42
    转: ... ******************** PY核心模块方法 ******************** os模块: os.remove() 删除文件  os.unlink() 删除文件  os.rename() 重命名文件  os.listdir() 列出指定目录下所
  • Python 模块大全(很详细!)

    万次阅读 多人点赞 2014-12-12 20:47:18
    转载:。。。。 Python的模块大全,很全,有详细介绍! 另外附Python两个教程 ...Python 网络程序开发  注意:有些模块是只能在Unix下才运行的(如:commands etc) 正文: 0.1. 关于本书0.2. 代码约定0.3. 关于

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 123,679
精华内容 49,471
关键字:

网络执行官模块