堡垒机

ぐ巨炮叔叔 提交于 2019-12-05 06:46:59

认识堡垒机

拓展两个知识点:

1、traceback:出异常,会具体打印出哪一行

traceback.print_exc()

2、getpass模块获取用户名:

uson@ubuntu:~$ python3
Python 3.6.8 (default, Aug 20 2019, 17:12:48) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import getpass
>>> getpass.getuser()
'uson'

3、Ubuntu配置用户的环境变量:

source:使当前shell读入路径为filepath的shell文件并依次执行文件中的所有语句,通常用于重新执行刚修改的初始化文件,使之立即生效,而不必注销并重新登录

命令行输入:mysql -uuson -pakaedu改成source .bashrc执行
# 每个用户目录下都有一个.bashrc文件
#(1)vim .bashrc  在最后新增一行命令行输入的东西: 
mysql -uuson -pakaedu
或者 python3 .../.../..../.py    # 保存文件的绝对路径abspath
# (2)执行.bashrc
source .bashrc

 

4、字典的用法补充:

val.get(kek) or str 获取字典key, 获取不到,选择or  ---->val为字典

val.get(key)

5、assert host_obj  断言,即要求host_obj必须存在,否则报错

当断言条件为假时,抛出异常AssertionError

6、本例用到yaml模块,安装pyyaml模块

7、本例数据库建造时用到枚举类型ChoiceType(),需要用到一个插件

from sqlalchemy_utils import ChoiceType

堡垒机环节:

堡垒机的作用:

1、不需要提供root密码给运维

2、记录用户操作记录(审计)

3、用户权限控制

只有堡垒机管理员知道root密码

记住,表结构设计好之前,不要写代码

配置文件一般只写配置(类似变量类的赋值语句),不写动作(func())

正文:

******下载paramiko(本质上就是封装了ssh)文件,我们用到demo.py文件和interactive.py文件,并修改

业务逻辑结构:

代码示例:

bin目录:

 1 操作流程:
 2 堡垒机用户及主机组之间的数据实例化,和关联:
 3 1、入口create_groups,不添加关联数据(注释bind_hosts/user_profiles):已实例化主机组   new_groups.yml
 4   add_groups,不添加关联数据(注释bind_hosts/user_profiles),添加主机组数据一条      add_groups.yml
 5 2、create_users,关联检测hostgroups,不关联bind_hosts数据,已实例化堡垒机用户    new_user2.yml
 6   已自动关联hostgroup,userprofile
 7 3、检测:create_groups中的user_profiles关联是否有问题
 8   取消注释user_profiles,新加一个主机组反关联检测user_profiles     add_groups2.yml
 9 
10 以上均无问题后,继续
11 bindhost关联所有
12 4、create_hosts      new_hosts.yml
13 5、create_remoteusers        new_remoteusers.yml
14 
15 6、BindHost>>>
Readme
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 # Author:Uson
 4 import os,sys
 5 
 6 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 7 print(BASE_DIR)
 8 
 9 sys.path.append(BASE_DIR)
10 
11 from modules.actions import excute_from_command_line
12 
13 if __name__ == '__main__':
14     #执行脚本命令行参数判断 python fuck_run.py syncdb
15     #argv[0]是脚本名fuck_run.py,argv[1]是第一个命令行参数syncdb
16     excute_from_command_line(sys.argv) #sys.argv #传进来的是列表形式
fuck_run.py
 1 #dict: many val = list[ {} ]
 2 #Chinese is not supported
 3 
 4 bind1:
 5   hostname: server1
 6   remote_users: #dict{[-,-]}        #{ [ {user1:...}, {user2:...} ] }
 7 #  [{'user1': None, 'auth_type': 'ssh-key', 'username': 'root'},
 8 #   {'username': 'alex', 'password': 'alex3714', 'user2': None, 'auth_type': 'ssh-password'}]
 9     - user1: #list[{:,:,}]            #- [ {user1:None, username:root, ...}, {}, ...]
10       username: root
11       auth_type: ssh-key
12       #password: 123
13     - user2: #[]
14       username: alex
15       auth_type: ssh-password
16       password: alex3714
17 #  remote_users:
18 #    - user1:
19 #        - username: root
20 #        - auth_type: ssh-key
21 #        - #password: 123
22 #    - user2:
23 #        - username: alex
24 #        - auth_type: ssh-password
25 #        - password: alex3714
26   groups:
27     - log_devteam
28   user_profiles:
29     - alex
30 
31 bind2:
32   hostname: server2
33   remote_users:
34     - user1:
35       username: alex
36       auth_type: ssh-password
37       password: alex3714
38 #  remote_users: dict{ [user1:[ username:alex, auth_type:ssh-password, ... ], [],  ...] }
39 #      - user1:
40 #          - username: alex
41 #          - auth_type: ssh-password
42 #          - password: alex3714
43 #item: {'user1': [{'username': 'alex'}, {'auth_type': 'ssh-password'}, {'password': 'alex3714'}]}  all is :key
44 #key: {'user1': [{'username': 'alex'}, {'auth_type': 'ssh-password'}, {'password': 'alex3714'}]}
45   groups:
46     - web_devteam
47     - mysql_devteam
48 
49   user_profiles:
50     - rain
Yaml配置文件样例 share_yml

conf目录:

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 # Author:Uson
 4 
 5 from modules import views, views_add
 6 
 7 '''
 8 本测试:
 9 (1)创建主机组,不创建binhost/userprofile
10 (2)创建用户,
11 '''
12 
13 actions = {
14     'syncdb': views.syncdb, #连接数据库,创建数据表 #(第一步)
15     'create_hosts': views.create_hosts,  # (第二步)
16     'create_remoteusers': views.create_remoteusers,  # (第三步)
17 
18     'create_users': views.create_users, #(第四步)
19     'create_groups': views.create_groups, #(第五步)
20 
21     'create_bindhosts': views.create_bindhosts, #(第六步)
22 
23     'start_session': views.start_session, #(第七步)
24 
25     # 'stop': views.stop_server, #(第八步)暂未实现
26 
27     'hand_modify': views.hand_modify, #暂未实现,只能创建不能修改     #一条一条手动输入修改,非文件提交
28 
29     # 'audit': views.log_audit, #查看所有运维人员的记录,暂未实现
30 
31     'add_groups': views_add.add_groups, #主机组添加数据,针对死循环,没有入口,不含关联数据
32 }
action_registers.py
1 #!/usr/bin/env python
2 # -*- coding:utf-8 -*-
3 # Author:Uson
4 import os,sys
5 
6 # BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
7 
8 ConnParams = "mysql+pymysql://uson:akaedu@192.168.1.6/uson_fuckdb?charset=utf8" #只写配置不写动作
settings

models目录:

  1 #!/usr/bin/env python
  2 # -*- coding:utf-8 -*-
  3 # Author:Uson
  4 '''堡垒机用户userprofile与hostgroup多对多关联'''
  5 from conf import settings
  6 from sqlalchemy import create_engine
  7 from sqlalchemy.ext.declarative import declarative_base
  8 from sqlalchemy import Column, Integer, String, Date, Table, Enum
  9 from sqlalchemy import ForeignKey, UniqueConstraint #联合唯一键
 10 from sqlalchemy.orm import relationship
 11 
 12 from sqlalchemy_utils import ChoiceType
 13 
 14 engine = create_engine(settings.ConnParams)
 15 Base = declarative_base()
 16 
 17 # '''(2)删除:多对多关联:第三方表的建设'''
 18 # Host_To_Remoteuser = Table(
 19 #     'host_to_remoteuser', Base.metadata,  #元数据,中介数据 == 实例化Metadata()后的metadata
 20 #     Column('host_id', Integer, ForeignKey('host.id')), #需要用,分隔
 21 #     Column('remoteuser_id', Integer, ForeignKey('remoteuser.id')), #需要用,分隔
 22 # )
 23 
 24 '''(3)多对多关联:堡垒机用户第三方表的建设'''
 25 Userprofile_To_Bindhost = Table(
 26     'userprofile_to_bindhost', Base.metadata,
 27     Column('userprofile_id', Integer, ForeignKey('userprofile.id')),
 28     Column('bindhost_id', Integer, ForeignKey('bindhost.id')),
 29 )
 30 '''(4)多对多关联:主机组第三方表的建设'''
 31 Bindhost_To_Hostgroup = Table(
 32     'bindhost_to_hostgroup', Base.metadata,
 33     Column('hostgroup_id', Integer, ForeignKey('hostgroup.id')),
 34     Column('bindhost_id', Integer, ForeignKey('bindhost.id')),
 35 )
 36 '''(5)多对多关联:主机组第三方表的建设,堡垒机用户userprofile与hostgroup多对多关联'''
 37 Userprofile_To_Hostgroup = Table(
 38     'userprofile_to_hostgroup', Base.metadata,
 39     Column('hostgroup_id', Integer, ForeignKey('hostgroup.id')),
 40     Column('userprofile_id', Integer, ForeignKey('userprofile.id')),
 41 )
 42 
 43 '''(2)新增一张表:存host,user, hostgroup'''
 44 class BindHost(Base):
 45     '''
 46         host        user    host_group
 47     192.168.1.1     web     bj_group
 48     192.168.1.1     log     sh_group
 49     '''
 50     __tablename__ = 'bindhost'
 51 
 52     '''联合唯一'''
 53     __table_args__ = (UniqueConstraint('host_id', 'hostgroup_id', 'remoteuser_id'),)  # 联合唯一键
 54 
 55     id = Column(Integer, primary_key=True)
 56     '''(2)不用第三张表的多对多方式:一条一个外键:多个外键多个关系'''
 57     host_id = Column(Integer, ForeignKey('host.id'))
 58     # hostgroup_id = Column(Integer, ForeignKey('hostgroup.id')) (4)
 59     remoteuser_id = Column(Integer, ForeignKey('remoteuser.id'))
 60 
 61     hosts = relationship("Host", backref = 'bind_hosts')
 62     # hostgroups = relationship("HostGroup", backref = 'bind_hosts') (4)
 63     remoteusers = relationship("RemoteUser", backref = 'bind_hosts')
 64     def __repr__(self):
 65         return "<%s - %s - %%s>" %(self.hosts.ip,
 66                                   # self.hostgroups.name, (4)
 67                                   self.remoteusers.username)
 68 
 69 '''堡垒机表结构   www.processon.com'''
 70 class Host(Base): #远程主机
 71     __tablename__ = 'host'
 72     id = Column(Integer, primary_key=True) #主键
 73     hostname = Column(String(32), unique=True) #主机名(非ip)唯一
 74     ip = Column(String(32), unique=True) #主机ip唯一
 75     port = Column(Integer, default=22) #端口号默认22
 76 
 77     # '''(2)删除:Host_To_Remoteuser'''
 78     # remote_users = relationship('RemoteUser', secondary = Host_To_Remoteuser, backref = 'hosts')
 79 
 80     def __repr__(self):
 81         return self.hostname
 82 class HostGroup(Base):#远程主机组
 83     __tablename__ = 'hostgroup'
 84     id = Column(Integer, primary_key=True)  # 主键
 85     name = Column(String(32), unique=True) #主机组名唯一
 86 
 87     '''(4)建立关系'''
 88     bindhosts = relationship("BindHost", seeondary = Bindhost_To_Hostgroup, backref = 'host_groups')
 89 
 90     def __repr__(self):
 91         return self.name
 92 class RemoteUser(Base):#远程主机用户
 93     __tablename__ = 'remoteuser'
 94 
 95     '''用户名和密码多对多关系:要使用联合唯一'''
 96     __table_args__ = (UniqueConstraint('auth_type', 'username', 'password'),)#联合唯一键
 97 
 98     id = Column(Integer, primary_key=True)  # 主键
 99 
100     # auth_type = Column(Enum(0,1))
101     '''认证类型:列表枚举型,经典案例,用到sqlalchemy_utils模块下的ChoiceType'''
102     AuthTypes = [
103         ('ssh-password', 'SSH/Password'),  # 前者写入数据库,后者显示给用户
104         ('ssh-key', 'SSH/KEY'),
105     ]
106     auth_type = Column(ChoiceType(AuthTypes)) #从列表中选择类型
107 
108     username = Column(String(32))  # 可以同用户名root,不同密码
109     password = Column(String(128)) # 可以同密码,不同用户名
110     def __repr__(self):
111         return self.username
112 class UserProfile(Base):#堡垒机用户
113     __tablename__ = 'userprofile'
114     id = Column(Integer, primary_key=True)  # 主键
115     username = Column(String(32), unique=True) #堡垒机用户名唯一
116     password = Column(String(128))
117 
118     '''(3)堡垒机用户第三张表建设'''
119     bindhosts = relationship("BindHost", secondary = Userprofile_To_Bindhost, backref = 'user_profiles')
120     '''(5)'''
121     hostgroups = relationship("HostGroup", secondary = Userprofile_To_Hostgroup, backref = 'user_profiles')
122     def __repr__(self):
123         return self.username
124 class Auditlog(Base): #堡垒机操作日志
125     __tablename__ = 'host'
126     id = Column(Integer, primary_key=True)  # 主键
127     def __repr__(self):
128         return self.id
129 
130 # Base.metadata.create_all(engine)  # 创建表结构
过程版
  1 #!/usr/bin/env python
  2 # -*- coding:utf-8 -*-
  3 # Author:Uson
  4 '''此例表结构与堡垒机案例表结构有出入,灵活运用'''
  5 from sqlalchemy.ext.declarative import declarative_base
  6 from sqlalchemy import Column, Integer, String, Date, Table, Enum, DateTime
  7 from sqlalchemy import ForeignKey, UniqueConstraint #联合唯一键
  8 from sqlalchemy.orm import relationship
  9 from sqlalchemy_utils import ChoiceType
 10 Base = declarative_base()
 11 
 12 Userprofile_To_Bindhost = Table(
 13     'userprofile_to_bindhost', Base.metadata,
 14     Column('userprofile_id', Integer, ForeignKey('userprofile.id')),
 15     Column('bindhost_id', Integer, ForeignKey('bindhost.id')),
 16 )
 17 
 18 Bindhost_To_Hostgroup = Table(
 19     'bindhost_to_hostgroup', Base.metadata,
 20     Column('hostgroup_id', Integer, ForeignKey('hostgroup.id')),
 21     Column('bindhost_id', Integer, ForeignKey('bindhost.id')),
 22 )
 23 
 24 Userprofile_To_Hostgroup = Table(
 25     'userprofile_to_hostgroup', Base.metadata,
 26     Column('hostgroup_id', Integer, ForeignKey('hostgroup.id')),
 27     Column('userprofile_id', Integer, ForeignKey('userprofile.id')),
 28 )
 29 
 30 class BindHost(Base):
 31     '''
 32         host        user    host_group
 33     192.168.1.1     web     x
 34     192.168.1.1     log     x
 35     '''
 36     __tablename__ = 'bindhost'
 37     __table_args__ = (UniqueConstraint('host_id', 'remoteuser_id', name='_host_remoteuser_uc'),)  # 联合唯一键
 38 
 39     id = Column(Integer, primary_key=True)
 40     host_id = Column(Integer, ForeignKey('host.id'))
 41     remoteuser_id = Column(Integer, ForeignKey('remoteuser.id'))
 42 
 43     hosts = relationship("Host", backref = 'bind_hosts')
 44     remoteusers = relationship("RemoteUser", backref = 'bind_hosts')
 45 
 46     audit_logs = relationship('AuditLog')
 47 
 48     # hostgroups = relationship("HostGroup", secondary = Bindhost_To_Hostgroup, backref = 'bind_hosts')
 49     def __repr__(self): #循环ip地址,远程用户
 50         return "<%s - %s - %s>" %(self.hosts.hostname,
 51                              self.remoteusers.username,
 52                              self.id)
 53 
 54 class Host(Base):
 55     __tablename__ = 'host'
 56     id = Column(Integer, primary_key=True)
 57     hostname = Column(String(32), unique=True)
 58     ip = Column(String(32), unique=True)
 59     port = Column(Integer, default=22)
 60 
 61     def __repr__(self):
 62         return self.hostname
 63 class HostGroup(Base):
 64     __tablename__ = 'hostgroup'
 65     id = Column(Integer, primary_key=True)
 66     name = Column(String(32), unique=True)
 67 
 68     bindhosts = relationship("BindHost", secondary = Bindhost_To_Hostgroup, backref = 'host_groups')
 69 
 70     def __repr__(self):
 71         return self.name
 72 class RemoteUser(Base):#远程主机用户
 73     __tablename__ = 'remoteuser'
 74 
 75     '''用户名和密码多对多关系:要使用联合唯一'''
 76     __table_args__ = (UniqueConstraint('auth_type', 'username', 'password', name='_authtype_usernm_pwd_uc'),)
 77 
 78     id = Column(Integer, primary_key=True)
 79     AuthTypes = [
 80         ('ssh-password', 'SSH/Password'),  # 前者写入数据库,后者显示给用户
 81         ('ssh-key', 'SSH/KEY'),
 82     ]
 83     auth_type = Column(ChoiceType(AuthTypes)) #从列表中选择类型 (需要实例化)
 84 
 85     username = Column(String(32))  # 可以同用户名root,不同密码    (需要实例化)
 86     password = Column(String(128)) # 可以同密码,不同用户名    (可以为NUll,根据类型选择实例化)
 87     def __repr__(self):
 88         return self.username
 89 
 90 class UserProfile(Base):#堡垒机用户
 91     __tablename__ = 'userprofile'
 92     id = Column(Integer, primary_key=True)  # 主键
 93     username = Column(String(32), unique=True) #堡垒机用户名唯一
 94     password = Column(String(128))
 95 
 96     '''secondary='',写表名'''
 97     '''secondary=,写开发者起的名字'''
 98     bindhosts = relationship("BindHost", secondary = Userprofile_To_Bindhost, backref = 'user_profiles')
 99     hostgroups = relationship("HostGroup", secondary = Userprofile_To_Hostgroup, backref = 'user_profiles')
100     def __repr__(self):
101         return self.username #[]
102 class AuditLog(Base): #堡垒机操作日志
103     __tablename__ = 'audit_log'
104     id = Column(Integer, primary_key=True)
105     user_id = Column(Integer, ForeignKey('userprofile.id')) #需要实例化
106     bind_host_id = Column(Integer, ForeignKey('bindhost.id')) #需要实例化
107 
108     '''枚举类型'''
109     # action_choices = [
110     #     (0, 'CMD'),
111     #     (1, 'Login'),
112     #     (2, 'Logout'),
113     #     (3, 'GetFile'),
114     #     (4, 'SendFile'),
115     #     (5, 'Exception'),
116     # ]
117     action_choices2 = [
118         ('cmd', 'CMD'), #python3默认是Unicode,不需要加u
119         ('login', 'Login'),
120         ('logout', 'Logout'),
121         # (3,'GetFile'),
122         # (4,'SendFile'),
123         # (5,'Exception'),
124     ]
125     action_type = Column(ChoiceType(action_choices2)) #需要实例化
126 
127     # action_type = Column(String(64))
128     cmd = Column(String(255)) #可选的,可为Null,类似密码密钥,如果不是cmd操作,login/logout:可以是NUll
129     date = Column(DateTime) #需要实例化
130 
131     user_profile = relationship("UserProfile")
132     bind_host = relationship("BindHost")
完整版

modules目录:

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 # Author:Uson
 4 from conf import action_registers
 5 from modules import utils
 6 def help_msg():
 7     '''
 8     print help msgs
 9     :return:
10     '''
11     print("\033[31;1m参数个数输入不合法:\033[0m")
12     '''循环打印配置中的命令字典'''
13     print("\033[32;1m请从以下选项中选择操作。\033[0m")
14     for key in action_registers.actions:
15         print('\t', key)
16 
17 def excute_from_command_line(argvs):
18     if len(argvs) < 2: #python fuck_run.py 列表长度
19         help_msg()
20         exit()
21     if argvs[1] not in action_registers.actions:
22         '''打印错误信息'''
23         utils.print_err("【%s】命令不存在"%argvs[1], quit = True)
24         # utils.print_err("Command [%s] does not exist!" % argvs[1], quit=True)
25     #命令存在的情况
26     # action_registers.actions[argvs[1]]() #可以不传参数
27     action_registers.actions[argvs[1]](argvs[1:]) #可以不传参数,但可以加个非固定参数(参数列表),增加函数的可拓展性
actions
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 # Author:Uson
 4 from  models import models
 5 from modules.db_conn import engine,session
 6 from modules.utils import print_err
 7 
 8 def bind_hosts_filter(vals):
 9     print('**>',vals.get('bind_hosts') )
10 
11     '''只能用于反查询'''
12     # bind_hosts2 = session.query(models.BindHost).filter(models.BindHost.hosts.hostname.in_(vals.get('bind_hosts') )).all()
13 
14     #仅返回hostname,无法关联
15     # bind_hosts = session.query(models.Host).filter(models.Host.hostname.in_(vals.get('bind_hosts'))).all()
16 
17     bind_hosts = session.query(models.BindHost).filter(models.Host.hostname.in_(vals.get('bind_hosts'))).all()
18     print("1:2对比:", bind_hosts)
19     # print("1:2对比:", bind_hosts)
20     if not bind_hosts:
21         # print_err("none of [%s] exist in bind_host table." % vals.get('bind_hosts'),quit=False)
22         print_err("未分组",quit=False)
23     return bind_hosts
24 
25 def user_profiles_filter(vals):
26     user_profiles = session.query(models.UserProfile).filter(models.UserProfile.username.in_(vals.get('user_profiles'))
27                                                              ).all()
28     if not user_profiles:
29         print_err("none of [%s] exist in user_profile table." % vals.get('user_profiles'),quit=True)
30     return  user_profiles
common_filters
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 # Author:Uson
 4 from sqlalchemy import create_engine
 5 from conf import settings
 6 
 7 from sqlalchemy.orm import sessionmaker
 8 
 9 engine = create_engine(settings.ConnParams)
10 
11 Session_class = sessionmaker(bind=engine)#创建与数据库的会话session class ,注意,这里返回给session的是个class,不是实例
12 session = Session_class()
db_conn
  1 # Copyright (C) 2003-2007  Robey Pointer <robeypointer@gmail.com>
  2 #
  3 # This file is part of paramiko.
  4 #
  5 # Paramiko is free software; you can redistribute it and/or modify it under the
  6 # terms of the GNU Lesser General Public License as published by the Free
  7 # Software Foundation; either version 2.1 of the License, or (at your option)
  8 # any later version.
  9 #
 10 # Paramiko is distributed in the hope that it will be useful, but WITHOUT ANY
 11 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 12 # A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
 13 # details.
 14 #
 15 # You should have received a copy of the GNU Lesser General Public License
 16 # along with Paramiko; if not, write to the Free Software Foundation, Inc.,
 17 # 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
 18 
 19 
 20 import socket
 21 import sys
 22 from paramiko.py3compat import u
 23 from  models import models
 24 import datetime
 25 
 26 # windows does not have termios...
 27 try:
 28     import termios
 29     import tty
 30     has_termios = True
 31 except ImportError:
 32     has_termios = False
 33 
 34 
 35 def interactive_shell(chan,user_obj,bind_host_obj,cmd_caches,log_recording):
 36     if has_termios:
 37         posix_shell(chan,user_obj,bind_host_obj,cmd_caches,log_recording)
 38     else:
 39         # windows_shell(chan)
 40         windows_shell(chan, user_obj,bind_host_obj,cmd_caches,log_recording)
 41 
 42 
 43 def posix_shell(chan,user_obj,bind_host_obj,cmd_caches,log_recording):
 44     import select
 45     
 46     oldtty = termios.tcgetattr(sys.stdin)
 47     try:
 48         tty.setraw(sys.stdin.fileno())
 49         tty.setcbreak(sys.stdin.fileno())
 50         chan.settimeout(0.0)
 51         cmd = ''
 52 
 53         tab_key = False
 54         while True:
 55             r, w, e = select.select([chan, sys.stdin], [], [])
 56             if chan in r:
 57                 try:
 58                     x = u(chan.recv(1024))
 59                     if tab_key:
 60                         if x not in ('\x07' , '\r\n'): #tab自动补全功能
 61                             print('tab:',x)
 62                             cmd += x
 63                         tab_key = False
 64                     if len(x) == 0:
 65                         sys.stdout.write('\r\n*** EOF\r\n')
 66                         break
 67                     sys.stdout.write(x)
 68                     sys.stdout.flush()
 69                 except socket.timeout:
 70                     pass
 71             if sys.stdin in r:
 72                 x = sys.stdin.read(1)
 73                 if '\r' != x:
 74                     cmd +=x
 75                 else:
 76 
 77                     print('cmd->:',cmd)
 78 
 79                     '''CMD记录实例化'''
 80                     log_item = models.AuditLog(user_id=user_obj.id,
 81                                           bind_host_id=bind_host_obj.id,
 82                                           action_type='cmd',
 83                                           cmd=cmd , #ls
 84                                           date=datetime.datetime.now()
 85                                           )
 86                     cmd_caches.append(log_item)
 87                     cmd = ''
 88 
 89                     if len(cmd_caches)>=10:
 90                         # log_recording(cmd_caches) #实际有用的就是cmd_caches,提交到数据库
 91                         log_recording(user_obj,bind_host_obj,cmd_caches)
 92                         cmd_caches = []
 93                 if '\t' == x:
 94                     tab_key = True
 95                 if len(x) == 0:
 96                     break
 97                 chan.send(x)
 98 
 99     finally:
100         termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)
101 
102     
103 # thanks to Mike Looijmans for this code
104 # def windows_shell(chan):
105 #     import threading
106 #
107 #     sys.stdout.write("Line-buffered terminal emulation. Press F6 or ^Z to send EOF.\r\n\r\n")
108 #
109 #     def writeall(sock):
110 #         while True:
111 #             data = sock.recv(256)
112 #             if not data:
113 #                 sys.stdout.write('\r\n*** EOF ***\r\n\r\n')
114 #                 sys.stdout.flush()
115 #                 break
116 #             sys.stdout.write(data.decode())
117 #             sys.stdout.flush()
118 #
119 #     writer = threading.Thread(target=writeall, args=(chan,))
120 #     writer.start()
121 #
122 #     try:
123 #         while True:
124 #             d = sys.stdin.read(1)
125 #             if not d:
126 #                 break
127 #             chan.send(d)
128 #     except EOFError:
129 #         # user hit ^Z or F6
130 #         pass
131 
132 def windows_shell(chan, user_obj,bind_host_obj,cmd_caches,log_recording):
133     import threading
134 
135     sys.stdout.write("Line-buffered terminal emulation. Press F6 or ^Z to send EOF.\r\n\r\n")
136 
137     def writeall(sock):
138         while True:
139             data = sock.recv(256) #我们不用记录输出结果
140             if not data:
141                 sys.stdout.write('\r\n*** EOF ***\r\n\r\n')
142                 sys.stdout.flush()
143                 break
144             sys.stdout.write(data.decode()) #屏幕输出命令结果
145             sys.stdout.flush()
146 
147     writer = threading.Thread(target=writeall, args=(chan, ))
148     writer.start()
149 
150     '''Windows版审计,自己实现》》'''
151     cmd = ''
152     try:
153         while True:
154             d = sys.stdin.read(1)
155             # print("D:", d)
156             if not d:
157                 break
158             cmd += d
159             # print("cmd:", cmd)
160             # if d == '' or d == '\r' or d == '\r\n' or d == '\n':
161             if d == '\n' or d == '\r\n': #windows回车显示是空格,但验证后,回车不等于'',而是'\n'
162                 # print("cmd_cmd:", cmd)
163                 '''CMD记录实例化'''
164                 log_item = models.AuditLog(user_id=user_obj.id,
165                                            bind_host_id=bind_host_obj.id,
166                                            action_type='cmd',
167                                            cmd=cmd,  # ls
168                                            date=datetime.datetime.now()
169                                            )
170                 cmd_caches.append(log_item)
171                 # print("cmd_caches:", cmd_caches, len(cmd_caches))
172                 cmd = ''
173 
174             if len(cmd_caches) >= 10 or cmd == 'exit' or cmd == '^Z':
175                 # log_recording(cmd_caches) #实际有用的就是cmd_caches,提交到数据库
176                 log_recording(user_obj, bind_host_obj, cmd_caches)
177                 cmd_caches = []
178             if sys.stdout.write('*** EOF ***'):
179                 log_recording(user_obj, bind_host_obj, cmd_caches)
180 
181             chan.send(d)
182     except EOFError:
183         # user hit ^Z or F6
184 
185         '''退出记录审计'''
186         log_recording(user_obj, bind_host_obj, cmd_caches)
187 
188         pass
interactive
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 # Author:Uson
 4 
 5 import base64
 6 import getpass
 7 import os
 8 import socket
 9 import sys
10 import traceback
11 from paramiko.py3compat import input
12 from  models import models
13 import datetime
14 
15 import paramiko
16 try:
17     import interactive
18 except ImportError:
19     from . import interactive #同级目录下用.
20 
21 def ssh_login(user_obj,bind_host_obj,mysql_engine,log_recording):
22     # now, connect and use paramiko Client to negotiate SSH2 across the connection
23     try:
24         client = paramiko.SSHClient()
25         client.load_system_host_keys()
26         client.set_missing_host_key_policy(paramiko.WarningPolicy())
27         print('*** Connecting...')
28         #client.connect(hostname, port, username, password)
29 
30         '''需要修改'''
31         client.connect(bind_host_obj.hosts.ip,
32                        bind_host_obj.hosts.port,
33                        bind_host_obj.remoteusers.username,
34                        bind_host_obj.remoteusers.password,
35                        timeout=30)
36 
37         cmd_caches = []
38         chan = client.invoke_shell()
39         print(repr(client.get_transport()))
40         print('*** Here we go!\n')
41 
42         '''日志模块:login记录实例化'''
43         '''interactive.py:CMD记录实例化'''
44         cmd_caches.append(models.AuditLog(user_id=user_obj.id,  #外键实例化
45                                           bind_host_id=bind_host_obj.id,    #外键实例化
46                                           action_type='login', #cmd是Null
47                                           date=datetime.datetime.now()
48                                           ))
49         log_recording(user_obj,bind_host_obj,cmd_caches)
50         interactive.interactive_shell(chan,user_obj,bind_host_obj,cmd_caches,log_recording)
51         chan.close()
52         client.close()
53 
54     except Exception as e:
55         print('*** Caught exception: %s: %s' % (e.__class__, e))
56         traceback.print_exc()
57         try:
58             client.close()
59         except:
60             pass
61         sys.exit(1)
ssh_login
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 # Author:Uson
 4 
 5 import yaml
 6 '''约定俗成'''
 7 try:
 8     from yaml import CLoader as Loader, CDumper as Dumper
 9 except ImportError:
10     from yaml import Loader, Dumper
11 
12 def print_err(msg, quit=False):
13     output = "\033[31;1mError:%s\033[0m" %msg
14     if quit:
15         exit(output)
16     else:
17         print(output)
18 
19 def yaml_parser(yml_filename):
20     '''
21     load yaml file and return
22     :param yml_filename:
23     :return:
24     '''
25     '''
26     #未创建hostgroup和bindhost,却给他们关联数据,会报错
27     #但会成功创建userprofile表
28     #'gbk' codec can't decode byte 0xaa in position 4: illegal multibyte sequence?
29     # yml 不支持添加中文注释
30     '''
31     # yml_filename = "%s/%s.yml" % (settings.StateFileBaseDir,yml_filename)
32     try:
33         print("读取文件")
34         yaml_file = open(yml_filename, 'r')
35         data = yaml.load(yaml_file)
36         print("返回字典数据")
37         return data
38     except Exception as e:
39         print_err(e)
utils
  1 #!/usr/bin/env python
  2 # -*- coding:utf-8 -*-
  3 # Author:Uson
  4 '''
  5 表示数据库已有此数据
  6 [SQL: INSERT INTO hostgroup (name) VALUES (%(name)s)]
  7 [parameters: {'name': 'web_devteam'}]
  8 (Background on this error at: http://sqlalche.me/e/gkpj)
  9 '''
 10 
 11 from models import models
 12 from modules.db_conn import engine, session
 13 from modules import utils, ssh_login, common_filters
 14 
 15 from models import models
 16 
 17 def welcome_msg(user):
 18     WELCOME_MSG = '''\033[32;1m
 19         ------------- %s登录成功 -------------
 20         \033[0m''' % user.username
 21     print(WELCOME_MSG)
 22 
 23 def auth():
 24     '''
 25         do the user login authentication
 26         :return:
 27         '''
 28     count = 0
 29     while count < 3:
 30         username = input("\033[32;1m堡垒机用户名:\033[0m").strip()
 31         if len(username) == 0: continue
 32         password = input("\033[32;1m堡垒机登录密码:\033[0m").strip()
 33         if len(password) == 0: continue
 34         user_obj = session.query(models.UserProfile).filter(
 35             models.UserProfile.username==username,
 36             models.UserProfile.password==password).first()
 37         #如果数据库存在用户账户,返回用户对象
 38         print("User_obj>>", user_obj)
 39         if user_obj:
 40             return user_obj
 41         else:
 42             # print("错误的用户名或密码,您还有%s次输入机会。" % (3 - (count + 1)))
 43             print("错误的用户名或密码,您还有%s次输入机会。" % (3 - count - 1))
 44             count += 1
 45     else:
 46         utils.print_err("登录错误次数过多,请稍后再试。")
 47 
 48 def hand_modify(argvs):
 49     '''
 50     格式:hand_modify -f 功能函数(create_remoteusers) modify_id modify_name modified_name
 51     :param argvs:
 52     :return:
 53     '''
 54     if '-f' in argvs:
 55         modify_table  = argvs[argvs.index("-f") +1 ]
 56         modify_id = int(argvs[argvs.index("-f") + 2])
 57         modify_name = argvs[argvs.index("-f") + 3]
 58         modified_name = argvs[argvs.index("-f") + 4]
 59         print("修改》》", modify_id, modify_table, modified_name, modify_name)
 60         if modify_table == 'create_hosts':
 61             pass
 62             # from models.models import Host
 63             # session.query(Host).filter(Host.modify_name)
 64         elif modify_table == 'create_remoteusers':
 65             # from models import models
 66             print("modify_id:", modify_id)
 67             obj = session.query(models.RemoteUser).filter(
 68                 models.RemoteUser.id==modify_id).first()
 69             # print("obj:", obj)
 70             # print("obj:")
 71             if modify_name == 'password':
 72                 obj.password = modified_name
 73             elif modify_name == 'auth_type':
 74                 print("auth_type>>>\n", obj.auth_type)
 75                 obj.auth_type = modified_name
 76             session.add(obj)
 77         elif modify_table == 'create_users':
 78             from models.models import UserProfile
 79         elif modify_table == 'create_groups':
 80             from models.models import HostGroup
 81     else:
 82         utils.print_err("invalid usage, should be:\n"
 83          "hand_modify -f 功能函数 modify_id modify_name modified_name",quit=True)
 84     print("hostgroup正在创建……")
 85     session.commit()
 86     print("hostgroup创建成功!")
 87 
 88     # source = utils.yaml_parser(modify_table)
 89     # print("modify_file - source:", source)
 90     # if source:
 91     #     for key,val in source.items():
 92     #         print("key,val:", key,val)
 93     #
 94     #         #判断key是否存在,存在,退出
 95     #         hostgroup = session.query(models.HostGroup).filter(
 96     #             models.HostGroup.name==key).first()
 97     #         if hostgroup:
 98     #             utils.print_err("该主机组已存在,不可重复添加。", quit = True)
 99     #         obj = models.HostGroup(name=key) #实例化主机组
100     #         print("obj:", obj)
101     #         session.add(obj)
102     #     print("hostgroup正在创建……")
103     #     session.commit()
104     #     print("hostgroup创建成功!")
105 
106 def stop_server():
107     pass
108 
109 def log_recording(user_obj,bind_host_obj,logs):
110     '''
111     flush user operations on remote host into DB
112     :param user_obj:
113     :param bind_host_obj:
114     :param logs: list format [logItem1,logItem2,...]
115     :return:
116     '''
117     print("\033[41;1m--logs:\033[0m",logs)
118     session.add_all(logs)
119     session.commit()
120 
121 def start_session(argvs): #登录认证,开启堡垒机会话操作远程主机
122     print('堡垒机会话登录认证!')
123     user = auth()
124     '''返回用户登录对象user_obj'''
125     if user:
126         welcome_msg(user) #类user.    #登录成功
127         '''打印主机分组信息'''
128         print("user.bindhosts:", user.bindhosts) #hosts.ip,remoteusers.username,remoteusers.auth_type
129         print(user.hostgroups) #name
130         exit_flag = False
131         while not exit_flag:
132             #未分组的主机列表
133             if user.bindhosts:
134                 print('\033[32;1mz.未分组主机 (%s)\033[0m' %len(user.bindhosts))
135             #分组的主机列表
136             for index, group in enumerate(user.hostgroups):
137                 print('\033[32;1m%s.\t%s (%s)\033[0m' %
138                       (index, group.name, len(group.bindhosts)))
139             print("选择编号查看主机列表》》")
140             choice = input("[%s]:" % user.username).strip()
141             if len(choice) == 0: continue
142             if choice == 'z':
143                 print("------ 分组: 未分组主机 ------")
144                 for index, bind_u_host in enumerate(user.bindhosts): #user.bindhosts是一个列表
145                     print("  %s.\t%s@%s(%s)" % (index,
146                                                 bind_u_host.remoteusers.username, #远程主机用户名
147                                                 bind_u_host.hosts.hostname, #远程主机名
148                                                 bind_u_host.hosts.ip, #远程主机ip地址
149                                                 ))
150                 print("----------- END -----------")
151 
152                 while not exit_flag:
153                     user_option = input("[(b)返回, (q)退出, 选择远程主机进行登录]:").strip()
154                     if len(user_option) == 0: continue
155                     if user_option == 'b': break
156                     if user_option == 'q': exit_flag = True
157                     if user_option.isdigit():
158                         user_option = int(user_option)
159                         # if type(choice) == str:
160                         #     choice = int(choice)
161                         if user_option < len(user.bindhosts):
162                             print('host:', user.bindhosts[user_option])
163                             '''日志表还没创建'''
164                             print('audit log:', user.bindhosts[user_option].audit_logs)
165                             '''接下来,登录远程主机操作'''
166                             ssh_login.ssh_login(user,
167                                                 user.bindhosts[user_option],
168                                                 session,
169                                                 log_recording)  # 这里只是传函数地址过去,并没有执行函数
170                         else:
171                             print("没有这样的主机编号...")
172 
173             elif choice.isdigit(): #输入的是主机分组编号
174                 choice = int(choice)
175                 if choice < len(user.hostgroups):
176                     print("------ 分组: %s ------"  % user.hostgroups[choice].name ) #第choice组
177                     for index,bind_host in enumerate(user.hostgroups[choice].bindhosts):
178                         print("  %s.\t%s@%s(%s)"%(index,
179                                                   bind_host.remoteusers.username,
180                                                   bind_host.hosts.hostname,
181                                                   bind_host.hosts.ip,
182                                                   ))
183                     print("----------- END -----------" )
184 
185                     #host selection
186                     '''选择远程主机进行登录'''
187                     while not exit_flag:
188                         user_option = input("[(b)返回, (q)退出, 选择远程主机进行登录]:").strip()
189                         if len(user_option)==0:continue
190                         if user_option == 'b':break
191                         if user_option == 'q':exit_flag=True
192                         if user_option.isdigit():
193                             user_option = int(user_option)
194                             # if type(choice) == str:
195                             #     choice = int(choice)
196                             if user_option < len(user.hostgroups[choice].bindhosts):
197                                 print('host:',user.hostgroups[choice].bindhosts[user_option])
198                                 '''日志表还没创建'''
199                                 print('audit log:',user.hostgroups[choice].bindhosts[user_option].audit_logs)
200                                 '''接下来,登录远程主机操作'''
201                                 ssh_login.ssh_login(user,
202                                                     user.hostgroups[choice].bindhosts[user_option],
203                                                     session,
204                                                     log_recording) #这里只是传函数地址过去,并没有执行函数
205                             else:
206                                 print("没有这样的主机编号...")
207         else:
208             print("没有这样的分组编号...")
209 
210 '''后来的函数往上写'''
211 def create_bindhosts(argvs):
212     '''
213     create bind hosts
214     :param argvs:
215     :return:
216     '''
217     if '-f' in argvs:
218         bindhosts_file  = argvs[argvs.index("-f") +1 ]
219     else:
220         utils.print_err("invalid usage, should be:\ncreate_hosts -f <the new bindhosts file>",quit=True)
221     source = utils.yaml_parser(bindhosts_file)
222     print("create_bindhosts - source:", source)
223     if source:
224         for key,val in source.items():
225             print("key,val:\n", key,val)
226             host_obj = session.query(models.Host).filter(models.Host.hostname==val.get('hostname')).first()
227             assert host_obj #断言,host_obj必须存在
228 
229             # print("get:\n",val.get('remote_users'))
230             # print("val:\n",val['remote_users']) #一模一样
231             # print("val2:\n",val['hostname'])
232 
233             for item in val['remote_users']: #是循环列表,而不再是循环字典了new_bindhosts.yml
234             # for item in val.get('remote_users'):
235                 print("item:", item ) #列表第一个元素[0]是字典类型 = 字典dict:item{}
236                 assert item.get('auth_type') #item{}
237                 if item.get('auth_type') == 'ssh-password':
238                     remoteuser_obj = session.query(models.RemoteUser).filter(
239                                                         models.RemoteUser.username==item.get('username'),
240                                                         models.RemoteUser.password==item.get('password')
241                                                     ).first()
242                 else:
243                     remoteuser_obj = session.query(models.RemoteUser).filter(
244                                                         models.RemoteUser.username==item.get('username'),
245                                                         models.RemoteUser.auth_type==item.get('auth_type'),
246                                                     ).first()
247                 if not remoteuser_obj:
248                     utils.print_err("RemoteUser obj %s does not exist." % item, quit=True)
249                 bindhost_obj = models.BindHost(host_id=host_obj.id,remoteuser_id=remoteuser_obj.id)
250                 session.add(bindhost_obj) #还没完,还有两个需要一起绑定了,再提交
251 
252                 #for groups this host binds to
253                 #判断source[key]与val是否相同 #是相同的
254                 # print("source[key]:\n", source[key])
255                 # print("val:\n", val)
256                 if source[key].get('groups'):
257                     #获取HostGroup类下这个source[key].get('groups')列表中的任意一个,key下面多个元素,以列表形式存放
258                     group_objs = session.query(models.HostGroup).filter(
259                         models.HostGroup.name.in_(source[key].get('groups') )).all()
260                     assert group_objs
261                     print('group_objs>>', group_objs)  #列表:[log_devteam]
262                     bindhost_obj.host_groups = group_objs #反查,第三张表建立多对多关系,需要列表赋值,同Author与Book
263                 #for user_profiles this host binds to
264                 '''同上'''
265                 if source[key].get('user_profiles'):
266                     userprofile_objs = session.query(models.UserProfile).filter(
267                         models.UserProfile.username.in_(source[key].get('user_profiles') )).all()
268                     # print("userprofile_objs1:", userprofile_objs)  # []
269                     assert userprofile_objs
270                     print("userprofile_objs:",userprofile_objs) #[]
271                     bindhost_obj.user_profiles = userprofile_objs #从BindHost反查堡垒机用户UserProfile
272                 print(bindhost_obj)
273         print("bindhost正在创建……")
274         session.commit()
275         print("bindhost创建成功!")
276 
277 def create_groups(argvs):
278     '''
279     create groups
280     :param argvs:
281     :return:
282     '''
283     if '-f' in argvs:
284         group_file  = argvs[argvs.index("-f") +1 ]
285     else:
286         utils.print_err("invalid usage, should be:\ncreategroups -f <the new groups file>",quit=True)
287     source = utils.yaml_parser(group_file)
288     print("create_groups - source:", source)
289     if source:
290         for key,val in source.items():
291             print(key,val)
292             obj = models.HostGroup(name=key) #实例化主机组
293             if val.get('bind_hosts'):
294                 bind_hosts = common_filters.bind_hosts_filter(val)
295                 obj.bind_hosts = bind_hosts
296 
297             if val.get('user_profiles'): #add_groups2.yml
298                 user_profiles = common_filters.user_profiles_filter(val)
299                 obj.user_profiles = user_profiles
300             session.add(obj)
301         print("hostgroup正在创建……")
302         session.commit()
303         print("hostgroup创建成功!")
304 
305 def create_users(argvs): #堡垒机用户创建
306     if '-f' in argvs:
307         user_file  = argvs[argvs.index("-f") +1 ]
308     else:
309         utils.print_err("invalid usage, should be:\ncreate_users -f <the new users file>", quit=True)
310     source = utils.yaml_parser(user_file)
311     print("create_users - source:", source)
312     if source:
313         for key,val in source.items():
314             print("key, val:", key,val)
315             print("key应该是类似:\nalex\nval应该是类似:\npassword: alex123\n"
316                   # "groups:- web_servers\t- db_servers")
317                   "groups:web_servers\tdb_servers") # - 被自动切除
318             obj = models.UserProfile(username=key, password=val.get('password')) #实例化堡垒机用户
319             #因为我是先创建的堡垒机用户,组还没有创建,所以第三张表Userprofile_To_Hostgroup无法关联
320 
321             #堡垒机用户alex有主机组的情况下
322             if val.get('groups'):
323                 groups_obj = session.query(models.HostGroup).filter(
324                     models.HostGroup.name.in_(val.get('groups'))).all()
325                 #获取HostGroup下所有主机组名,并判断是否在groups[]中,如果在,关联,不在报错
326                 # 即判断groups下主机组名是否存在主机组表中,如果在,全部获取出来
327                 print("所有主机组名 - groups_obj:", groups_obj)#[mysql_devteam, web_devteam]
328                 if not groups_obj: #[]空
329                     utils.print_err("none of [%s] exist in group table." % val.get('groups'), quit=True)
330                     # 本次明显找不到主机组名,还没创建呢,怎么关联
331                 obj.hostgroups = groups_obj #[]全部添加进去
332                 print("主机组名不存在,直接退出,应该不会执行到这里。userprofile数据也不会被创建")
333 
334             # 堡垒机用户alex有bindhost的情况下
335             if val.get('bind_hosts'):
336                 bind_hosts = common_filters.bind_hosts_filter(val)
337                 print("bind_hosts:", bind_hosts)
338                 print("obj.bindhosts:", obj.bindhosts)
339                 obj.bindhosts = bind_hosts
340             print("堡垒机用户obj:", obj)
341 
342             session.add(obj)
343         print("user正在创建……")
344         session.commit()
345         print("user创建成功!")
346 
347 def create_remoteusers(argvs):# 创建远程主机用户账户
348     if '-f' in argvs:
349         remoteusers_file  = argvs[argvs.index("-f") +1 ]
350     else:
351         utils.print_err("invalid usage, should be:\ncreate_remoteusers -f <the new remoteusers file>", quit=True)
352     source = utils.yaml_parser(remoteusers_file)
353     print("create_remoteusers - source>>", source)  # 已经把文件内容转成了字典格式
354     if source:
355         for key,val in source.items():
356             print("key,val:", key, val)
357             obj = models.RemoteUser(username=val.get('username'),auth_type=val.get('auth_type'),password=val.get('password'))
358             # obj = models.RemoteUser(username=val.get('username'),auth_type=val.get('auth_type'),
359             #                         password=val.get('password') or '已设定密钥登录')
360             session.add(obj) #username
361             print("remoteusers OBJ:username>>>>>", obj)
362         print("remoteusers正在创建……")
363         session.commit()
364         print("remoteusers创建成功!")
365 
366 def create_hosts(argvs):# 创建远程主机信息
367     if '-f' in argvs:
368         hosts_file  = argvs[argvs.index("-f") +1 ]  #-f hosts.yml主机信息字典文件
369     else:
370         utils.print_err("不合法的命令参数,应该这样写:\ncreate_hosts -f 新主机信息文件名", quit=True)
371     source = utils.yaml_parser(hosts_file) #把host文件名传过去 错误提示:因为判断else情况下,hosts_file不存在
372     print("create_hosts - source>>", source) #已经把文件内容转成了字典格式
373     if source:
374         for key,val in source.items(): #循环字典内容
375             print("key,val:", key,val)
376             #'''实例化远程主机'''
377             host_obj = models.Host(hostname=key, ip=val.get('ip_addr'), port=val.get('port') or 22)
378             print("实例化对象host_obj:", host_obj) #Host return - key: server1
379             session.add(host_obj)
380         print("hosts正在创建……")
381         session.commit()
382         print("hosts创建成功!")
383     else:
384         utils.print_err("host主机文件为空", quit = True)
385 
386 def syncdb(argvs):#传来的是一个列表,所以不需要用非固定参数来了
387     # def syncdb(*args): #非固定参数用法
388     print("正在进行表结构创建....")
389     models.Base.metadata.create_all(engine)  # 创建所有表结构
390     print("\033[32;1m表结构创建完成。\033[0m")
views
 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 # Author:Uson
 4 from models import models
 5 from modules.db_conn import engine, session
 6 from modules import utils, ssh_login, common_filters
 7 
 8 def add_groups(argvs):
 9     '''
10     add groups
11     :param argvs:
12     :return:
13     '''
14     if '-f' in argvs:
15         group_file  = argvs[argvs.index("-f") +1 ]
16     else:
17         utils.print_err("invalid usage, should be:\nadd_groups -f <the new groups file>",quit=True)
18     source = utils.yaml_parser(group_file)
19     print("add_groups - source:", source)
20     if source:
21         for key,val in source.items():
22             print(key,val)
23 
24             #判断key是否存在,存在,退出
25             hostgroup = session.query(models.HostGroup).filter(
26                 models.HostGroup.name==key).first()
27             if hostgroup:
28                 utils.print_err("该主机组已存在,不可重复添加。", quit = True)
29             obj = models.HostGroup(name=key) #实例化主机组
30             print("obj:", obj)
31             # if val.get('bind_hosts'):
32             #     bind_hosts = common_filters.bind_hosts_filter(val)
33             #     obj.bind_hosts = bind_hosts
34             #
35             # if val.get('user_profiles'):
36             #     user_profiles = common_filters.user_profiles_filter(val)
37             #     obj.user_profiles = user_profiles
38             session.add(obj)
39         print("hostgroup正在创建……")
40         session.commit()
41         print("hostgroup创建成功!")
views_add

结构分析构造:

 1 阶段分析》》》
 2 表结构1:models-v1.py
 3 初始化表结构,确定之间的关系(多对多,一对多,一对一)及数量(几个类class)
 4 涉及用户名密码联合唯一
 5 实现主机到远程用户的多对多关联:models-v1-1.py
 6 问题来了:主机和主机组实现多对多关联,如果我只想给alex(属于bj_group)192.168.1.3下的web访问权限
 7         但是现在,多对多关联,bj_group下的用户对应多个主机下的多个远程用户登录信息
 8         所以,主机和主机组不能直接关联
 9     host        host_group      user
10 192.168.1.1     bj_group        root
11 192.168.1.3     bj_group        web
12 192.168.1.3     bj_group        log
13 192.168.1.2     sh_group        mysql
14 
15 表结构4:models-v2.py
16 删除:主机到远程用户的多对多关联
17 一个主机ip对应多个不同账户name_pwd
18 一个账户name_pwd对应多个主机ip
19 一个主机ip对应多个主机组group
20 一个主机组group对应多个主机ip
21 双向一对多,就是多对多(三者联合唯一)
22 name        pwd         ip          host_group
23 root        abc       1.2.3.4       bj_group
24 mysql       acd       1.2.3.4       sh_group
25 web         aef       1.6.3.4       bj_group
26 root        abc       1.4.7.7       sh_group
27 
28 表结构5:models-v3.py
29 '''注意:外键关联:实现堡垒机用户的多对多关联(第三张表)'''
30 '''问题来了:每登录一台主机,都要带着一个主机分组,那么未分组主机就不能登录
31 未分组主机【10】  是不在该用户权限下的广州分组中的其中10个主机
32 北京分组【40】
33 上海分组【100】
34 ---------------
35 广州分组【200】
36 南京分组【30】
37 '''
38 
39 表结构5-5:models-v4.py  (4)
40 Bindhost 与 hostgroup多对多关联
41 
42 表结构6:models-v5.py (5)= models.py
43 堡垒机用户userprofile与hostgroup多对多关联
View Code

 

完整代码下载:暂无

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!