一、实际生产的架构图

1、生产环境为什么要这样干

  1. 解耦
  2. 异步

2、常用的queue软件

  1. redis, rabbitmq
  2. github ,
  3. restful API
  4. celery

二、我们今天如何实现?

1、实现思路

问题:views和web之间已返回,线程这里就断开了,那是因为你用django又启了一个线程

怎样才启动一个独立的进程,和django是没有关系,只不过是用django启动的,由操作系统来管理

三、目录结构

四、代码实现

1、backend

1、main

import subprocess
from web import models
from django.contrib.auth import authenticate
import random,string,uuidclass HostManager(object):"""用户登陆堡垒机后的交互程序"""def __init__(self):self.user = Nonedef get_session_id(self,bind_host_obj,tag):'''apply  session id'''session_obj = models.Session(user_id = self.user.id,bind_host=bind_host_obj,tag=tag)session_obj.save()return session_objdef interactive(self):"""交互脚本"""print("----run---------")count = 0while count <3:username = input("Username:").strip()password = input("Password:").strip()user = authenticate(username=username,password=password)if user:print("Welcome %s".center(50,'-') % user.name )self.user = userbreakelse:print("Wrong username or password!")count += 1else:exit("Too many attempts, bye.")if self.user: #验证成功while True:for index,host_group  in enumerate(self.user.host_groups.all()): #select_related()print("%s.\t%s[%s]" %(index,host_group.name, host_group.bind_hosts.count()))print("z.\t未分组主机[%s]" %(self.user.bind_hosts.count()))choice = input("%s>>:"% self.user.name).strip()if len(choice) == 0:continueselected_host_group = Noneif choice.isdigit():choice = int(choice)if choice >=0 and choice <= index: #合法选项selected_host_group = self.user.host_groups.all()[choice]elif choice == 'z':selected_host_group = self.userif selected_host_group:print("selected host group", selected_host_group)while True:for index, bind_host in enumerate(selected_host_group.bind_hosts.all()):print("%s.\t%s" % (index, bind_host))choice = choice = input("%s>>>:" % self.user.name).strip()if choice.isdigit():choice = int(choice)if choice >= 0 and choice <= index:  # 合法选项print("going to logon ....", selected_host_group.bind_hosts.all()[choice])bind_host = selected_host_group.bind_hosts.all()[choice]ssh_tag  = uuid.uuid4()session_obj =  self.get_session_id(bind_host,ssh_tag)monitor_script = subprocess.Popen("sh /opt/CrazyEye/backend/session_tracker.sh %s %s" % (ssh_tag,session_obj.id),shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)#print(monitor_script.stderr.read()) subprocess.run('sshpass -p %s ssh %s@%s -E %s -o  StrictHostKeyChecking=no' %(bind_host.remote_user.password,bind_host.remote_user.username,bind_host.host.ip_addr ,ssh_tag ), shell=True)elif choice == 'b':break

2、task_manager

import json,os ,subprocess
from django import conf
from web import modelsclass MultiTaskManger(object):"""负责解析并触发批量任务"""def __init__(self,request):self.request = requestself.call_task()def task_parser(self):"""解析任务"""self.task_data = json.loads(self.request.POST.get("task_data"))def call_task(self):self.task_parser()if self.task_data['task_type'] == 0:#cmdself.cmd_task()elif self.task_data['task_type'] == 1:#file transferself.file_transfer_task()def cmd_task(self):"""1.生产任务id2.触发任务3.返回任务id:return:"""task_obj = models.Task.objects.create(user=self.request.user,task_type=self.task_data['task_type'],content = self.task_data["cmd"])sub_task_objs = []for host_id in self.task_data['selected_host_ids']       :sub_task_objs.append(models.TaskLogDetail(task=task_obj,bind_host_id=host_id,result='init...',status=2))models.TaskLogDetail.objects.bulk_create(sub_task_objs)task_script_obj = subprocess.Popen("python %s %s" %(conf.settings.MULTITASK_SCRIPT,task_obj.id),shell=True,stdout=subprocess.PIPE)self.task = task_objdef file_transfer_task(self):"""1.生产任务记录2.触发任务3. 返回任务id:return:"""task_obj = models.Task.objects.create(user=self.request.user,task_type=self.task_data['task_type'],content=json.dumps(self.task_data))sub_task_objs = []for host_id in self.task_data['selected_host_ids']:sub_task_objs.append(models.TaskLogDetail(task=task_obj, bind_host_id=host_id, result='init...', status=2))models.TaskLogDetail.objects.bulk_create(sub_task_objs)task_script_obj = subprocess.Popen("python %s %s" % (conf.settings.MULTITASK_SCRIPT, task_obj.id),shell=True, stdout=subprocess.PIPE)self.task = task_obj

3、task_runner  

import sys ,os
import time,json
from concurrent.futures  import ThreadPoolExecutorimport paramikodef  ssh_cmd(task_log_obj):host = task_log_obj.bind_host.hostuser_obj = task_log_obj.bind_host.remote_usertry:ssh = paramiko.SSHClient()ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())ssh.connect(host.ip_addr, host.port, user_obj.username, user_obj.password,timeout=10)stdin, stdout, stderr = ssh.exec_command(task_log_obj.task.content)stdout_res = stdout.read()stderr_res = stderr.read()result = stdout_res + stderr_resprint(result)task_log_obj.result = resulttask_log_obj.status = 0ssh.close()except Exception as e :task_log_obj.result = etask_log_obj.status = 1task_log_obj.save()def file_transfer(task_log_obj):host = task_log_obj.bind_host.hostuser_obj = task_log_obj.bind_host.remote_usertry:t = paramiko.Transport((host.ip_addr, host.port))t.connect(username=user_obj.username, password=user_obj.password)sftp = paramiko.SFTPClient.from_transport(t)task_data = json.loads(task_log_obj.task.content)if task_data['file_transfer_type'] == 'send':sftp.put(task_data['local_file_path'],task_data['remote_file_path'])task_log_obj.result = "send local file [%s] to remote [%s] succeeded!" %(task_data['local_file_path'],task_data['remote_file_path'])else: #getlocal_file_path = "%s/%s" %(django.conf.settings.DOWNLOAD_DIR,task_log_obj.task.id)if not os.path.isdir(local_file_path):os.mkdir(local_file_path)file_name = task_data['remote_file_path'].split('/')[-1]sftp.get(task_data['remote_file_path'], "%s/%s.%s" %(local_file_path,host.ip_addr,file_name))task_log_obj.result = "get remote file [%s] succeeded" %(task_data['remote_file_path'])t.close()task_log_obj.status = 0except Exception as e:task_log_obj.result = etask_log_obj.status = 1task_log_obj.save()if __name__ == '__main__':base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))sys.path.append(base_dir)os.environ.setdefault("DJANGO_SETTINGS_MODULE", "CrazyEye.settings")import djangodjango.setup()from django import conffrom web import modelsif len(sys.argv) ==  1:exit("error:must provide task_id!")task_id = sys.argv[1]task_obj = models.Task.objects.get(id=task_id)#1. 生产多线程pool = ThreadPoolExecutor(10)if task_obj.task_type == 0:#cmdthread_func = ssh_cmdelse: #file_transferthread_func = file_transferfor task_log_detail_obj in task_obj.tasklogdetail_set.all():pool.submit(thread_func,task_log_detail_obj)#ssh_cmd(task_log_detail_obj)pool.shutdown(wait=True)

2、CrazyEye

1、settings

  1 import os
  2
  3 # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
  4 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
  5
  6
  7 # Quick-start development settings - unsuitable for production
  8 # See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/
  9
 10 # SECURITY WARNING: keep the secret key used in production secret!
 11 SECRET_KEY = 'c+lq-s!5j1($4zj+_3icw1xwr)yt#%x%&um#!e!b*-*5x(0&3a'
 12
 13 # SECURITY WARNING: don't run with debug turned on in production!
 14 DEBUG = True
 15
 16 ALLOWED_HOSTS = ["*"]
 17
 18
 19 # Application definition
 20
 21 INSTALLED_APPS = [
 22     'django.contrib.admin',
 23     'django.contrib.auth',
 24     'django.contrib.contenttypes',
 25     'django.contrib.sessions',
 26     'django.contrib.messages',
 27     'django.contrib.staticfiles',
 28     'web',
 29 ]
 30
 31 MIDDLEWARE = [
 32     'django.middleware.security.SecurityMiddleware',
 33     'django.contrib.sessions.middleware.SessionMiddleware',
 34     'django.middleware.common.CommonMiddleware',
 35     'django.middleware.csrf.CsrfViewMiddleware',
 36     'django.contrib.auth.middleware.AuthenticationMiddleware',
 37     'django.contrib.messages.middleware.MessageMiddleware',
 38     'django.middleware.clickjacking.XFrameOptionsMiddleware',
 39 ]
 40
 41 ROOT_URLCONF = 'CrazyEye.urls'
 42
 43 TEMPLATES = [
 44     {
 45         'BACKEND': 'django.template.backends.django.DjangoTemplates',
 46         'DIRS': [os.path.join(BASE_DIR, 'templates')]
 47         ,
 48         'APP_DIRS': True,
 49         'OPTIONS': {
 50             'context_processors': [
 51                 'django.template.context_processors.debug',
 52                 'django.template.context_processors.request',
 53                 'django.contrib.auth.context_processors.auth',
 54                 'django.contrib.messages.context_processors.messages',
 55             ],
 56         },
 57     },
 58 ]
 59
 60 WSGI_APPLICATION = 'CrazyEye.wsgi.application'
 61
 62
 63 # Database
 64 # https://docs.djangoproject.com/en/1.10/ref/settings/#databases
 65
 66 DATABASES = {
 67     'default': {
 68         'ENGINE': 'django.db.backends.sqlite3',
 69         'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
 70     }
 71 }
 72
 73
 74 # Password validation
 75 # https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators
 76
 77 AUTH_PASSWORD_VALIDATORS = [
 78     {
 79         'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
 80     },
 81     {
 82         'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
 83     },
 84     {
 85         'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
 86     },
 87     {
 88         'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
 89     },
 90 ]
 91
 92
 93 # Internationalization
 94 # https://docs.djangoproject.com/en/1.10/topics/i18n/
 95
 96 LANGUAGE_CODE = 'en-us'
 97
 98 TIME_ZONE = 'UTC'
 99
100 USE_I18N = True
101
102 USE_L10N = True
103
104 USE_TZ = True
105
106
107 # Static files (CSS, JavaScript, Images)
108 # https://docs.djangoproject.com/en/1.10/howto/static-files/
109
110 STATIC_URL = '/static/'
111
112 STATICFILES_DIRS = (
113     os.path.join(BASE_DIR,'statics'),
114 )
115
116
117 AUTH_USER_MODEL = 'web.UserProfile'
118
119 AUDIT_LOG_DIR = os.path.join(BASE_DIR,'log')
120 MULTITASK_SCRIPT= os.path.join(BASE_DIR,'backend/task_runner.py')
121
122 DOWNLOAD_DIR = os.path.join(BASE_DIR,'downloads')
123
124
125 LOGIN_URL = "/login/"

settings

2、urls

from django.conf.urls import url
from django.contrib import admin
from web import viewsurlpatterns = [url(r'^admin/', admin.site.urls),url(r'^$', views.dashboard),url(r'^user_audit/$', views.user_audit,name="user_audit"),url(r'^audit_log/(\w+-\w+-\w+)/$', views.audit_log_date,name="audit_log_date"),url(r'^audit_log/(\w+-\w+-\w+)/(\d+)/$', views.audit_log_detail,name="audit_log_detail"),url(r'^webssh/$', views.webssh,name="webssh"),url(r'^multitask/cmd/$', views.multitask_cmd,name="multitask_cmd"),url(r'^multitask/file_transfer/$', views.multitask_file_transfer,name="multitask_file_transfer"),url(r'^multitask/$', views.multitask,name="multitask"),url(r'^multitask/result/$', views.multitask_result,name="task_result"),url(r'^login/$', views.acc_login),url(r'^logout/$', views.acc_logout,name="logout"),]

3、templates

1、multitack_cmd.html

{% extends 'index.html' %}{% block page-title %}主机管理|批量命令{% endblock %}{% block page-content %}{% csrf_token %}<div class="row">{% include 'multitask_host_list_component.html' %}<div class="col-lg-8"><div class="panel"><div class="panel-heading"><h3 class="panel-title">命令操作</h3></div><div class="panel-body"><textarea id="cmd_text" class="form-control"></textarea><input type="button" id='post_task_btn'  οnclick="PostTask(this,'cmd')" class="btn btn-success pull-right" value="执行命令"></div></div><div class="panel"><div class="panel-heading"><h3 class="panel-title">任务结果</h3></div><div class="panel-body"><ul id="task_result_container"></ul></div></div></div></div>{% include 'multitask_js_component.html' %}{% endblock %}

2、multitask_host_list_component

    <div class="col-lg-4"><div class="panel"><div class="panel-heading"><h3 class="panel-title">主机列表</h3></div><div class="panel-body"><div class="list-group bord-no"><a οnclick="HostListDisplayToggle(this)" class="list-group-item " href="#"><input type="checkbox" οnclick="SelectGroup(this)">未分组主机<span class="badge badge-primary">{{ request.user.bind_hosts.count }}</span></a><ol class="hide">{% for bind_host in request.user.bind_hosts.all %}<li><input type="checkbox"  select_host="true" value="{{ bind_host.id }}">{{ bind_host.host.hostname }}({{ bind_host.host.ip_addr }})@{{ bind_host.remote_user.username}}</li>{% endfor %}</ol>{% for host_group in request.user.host_groups.select_related %}<a οnclick="HostListDisplayToggle(this)" class="list-group-item " href="#"><input type="checkbox" οnclick="SelectGroup(this)">{{ host_group.name }}<span class="badge badge-primary">{{ host_group.bind_hosts.count }}</span></a><ol class="hide">{% for bind_host in host_group.bind_hosts.all %}<li><input type="checkbox"  select_host="true" value="{{ bind_host.id }}">{{ bind_host.host.hostname }}({{ bind_host.host.ip_addr }})@{{ bind_host.remote_user.username}}</li>{% endfor %}</ol>{% endfor %}</div></div></div></div>

3、multitask_js_component

<script>function SelectFileTransferType(ele) {if ($(ele).val() == 'get'){$("#local_file_path").addClass("hide");}else {$("#local_file_path").removeClass("hide");}}function HostListDisplayToggle(ele) {$(ele).next().toggleClass("hide");}function SelectGroup(ele) {$(ele).parent().next().find("input").prop("checked",$(ele).prop("checked"))}function  GetTaskResult(task_id) {$.getJSON( "{% url 'task_result'  %}" ,{'task_id':task_id},function(callback){console.log( callback);var all_task_done = true;$.each(callback,function (index,ele) {var li_ele = $("li[bind_host_id='"+  ele['id'] +"']");li_ele.next().text(ele['result']);$(li_ele.children()[0]).text(ele.status);if ( ele.status == 2 ){all_task_done = false; //有任务未完成}})if (all_task_done){clearInterval(ResultRefreshObj);$("#post_task_btn").removeClass("disabled");}});//end getJSON}function PostTask(ele,task_type) {var selected_host_ids  = [];$("input[select_host]:checked").each(function () {selected_host_ids.push( $(this).val()  );})console.log(selected_host_ids)if (selected_host_ids.length == 0){alert("必须选择主机!")return false}if (task_type == "cmd"){var cmd_text = $("#cmd_text").val().trim();if (cmd_text.length == 0){alert("必须输入要执行的命令!")return false}var task_arguments = {'selected_host_ids' : selected_host_ids,'task_type':0 ,//cmd'cmd': cmd_text,}}else {var file_transfer_type = $("select[name='file_transfer_type']").val()var local_file_path = $("#local_file_path").val().trim()var remote_file_path = $("#remote_file_path").val().trim()if (file_transfer_type == "send"){if (local_file_path.length == 0){alert("必须输入本地文件路径!")return false}}if (remote_file_path.length == 0){alert("必须输入远程文件路径!")return false}var task_arguments = {'selected_host_ids' : selected_host_ids,'task_type':1 ,//file_transfer'file_transfer_type': file_transfer_type,'local_file_path':local_file_path,'remote_file_path':remote_file_path}}//再此任务执行完成前,不允许再提交新任务$(ele).addClass("disabled")//提交新任务之前情况任务结果面版$("#task_result_container").empty();$.post("{%  url 'multitask' %}"  , {'task_data':JSON.stringify(task_arguments),'csrfmiddlewaretoken':$("input[name='csrfmiddlewaretoken']").val() },function(callback){console.log(callback);var callback = JSON.parse(callback);$.each(callback.selected_hosts,function (index,ele) {var li_ele = "<li bind_host_id='"+ ele['id'] +"'>Host:" + ele.bind_host__host__hostname + "(" +ele.bind_host__host__ip_addr +")----------------<span></span></li><pre>sdff</pre>" ;$("#task_result_container").append(li_ele);})//去后端定时拿结果ResultRefreshObj = setInterval(function () {GetTaskResult(callback.task_id);},2000);});//end post}</script>

4、web

1、admin

  1 from django.contrib import admin
  2
  3 from web import models
  4 # Register your models here.
  5
  6
  7 from django import forms
  8 from django.contrib import admin
  9 from django.contrib.auth.models import Group
 10 from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
 11 from django.contrib.auth.forms import ReadOnlyPasswordHashField
 12
 13 from web.models import UserProfile
 14
 15
 16 class UserCreationForm(forms.ModelForm):
 17     """A form for creating new users. Includes all the required
 18     fields, plus a repeated password."""
 19     password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
 20     password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
 21
 22     class Meta:
 23         model = UserProfile
 24         fields = ('email', 'name')
 25
 26     def clean_password2(self):
 27         # Check that the two password entries match
 28         password1 = self.cleaned_data.get("password1")
 29         password2 = self.cleaned_data.get("password2")
 30         if password1 and password2 and password1 != password2:
 31             raise forms.ValidationError("Passwords don't match")
 32         return password2
 33
 34     def save(self, commit=True):
 35         # Save the provided password in hashed format
 36         user = super(UserCreationForm, self).save(commit=False)
 37         user.set_password(self.cleaned_data["password1"])
 38         if commit:
 39             user.save()
 40         return user
 41
 42
 43 class UserChangeForm(forms.ModelForm):
 44     """A form for updating users. Includes all the fields on
 45     the user, but replaces the password field with admin's
 46     password hash display field.
 47     """
 48     password = ReadOnlyPasswordHashField()
 49
 50     class Meta:
 51         model = UserProfile
 52         fields = ('email', 'password', 'name', 'is_active', 'is_admin')
 53
 54     def clean_password(self):
 55         # Regardless of what the user provides, return the initial value.
 56         # This is done here, rather than on the field, because the
 57         # field does not have access to the initial value
 58         return self.initial["password"]
 59
 60
 61 class UserProfileAdmin(BaseUserAdmin):
 62     # The forms to add and change user instances
 63     form = UserChangeForm
 64     add_form = UserCreationForm
 65
 66     # The fields to be used in displaying the User model.
 67     # These override the definitions on the base UserAdmin
 68     # that reference specific fields on auth.User.
 69     list_display = ('email', 'name','is_staff', 'is_admin')
 70     list_filter = ('is_admin','is_staff')
 71     fieldsets = (
 72         (None, {'fields': ('email', 'password')}),
 73         ('Personal info', {'fields': ('name',)}),
 74         ('堡垒机主机授权', {'fields': ('bind_hosts','host_groups')}),
 75         ('Permissions', {'fields': ('is_admin','is_staff','user_permissions','groups')}),
 76     )
 77     # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
 78     # overrides get_fieldsets to use this attribute when creating a user.
 79     add_fieldsets = (
 80         (None, {
 81             'classes': ('wide',),
 82             'fields': ('email', 'name', 'password1', 'password2')}
 83         ),
 84     )
 85     search_fields = ('email',)
 86     ordering = ('email',)
 87     filter_horizontal = ('user_permissions','groups','bind_hosts','host_groups')
 88
 89 # Now register the new UserAdmin...
 90 admin.site.register(models.UserProfile, UserProfileAdmin)
 91 # ... and, since we're not using Django's built-in permissions,
 92 # unregister the Group model from admin.
 93 admin.site.unregister(Group)
 94
 95
 96
 97 class RemoteUserAdmin(admin.ModelAdmin):
 98     list_display = ('username','auth_type','password')
 99
100
101 class TaskAdmin(admin.ModelAdmin):
102     list_display = ['id','user','task_type','content','date']
103
104
105 class TaskLogDetailAdmin(admin.ModelAdmin):
106     list_display = ['id','task','bind_host','result','status','start_date','end_date']
107
108
109 admin.site.register(models.Host)
110 admin.site.register(models.HostGroup)
111 admin.site.register(models.BindHost)
112 admin.site.register(models.RemoteUser,RemoteUserAdmin)
113 admin.site.register(models.IDC)
114 admin.site.register(models.Session)
115 admin.site.register(models.Task,TaskAdmin)
116 admin.site.register(models.TaskLogDetail,TaskLogDetailAdmin)

View Code

2、models

  1 from django.db import models
  2 from django.contrib.auth.models import User
  3
  4 from django.contrib.auth.models import (
  5     BaseUserManager, AbstractBaseUser,PermissionsMixin
  6 )
  7
  8
  9
 10 # Create your models here.
 11
 12 class IDC(models.Model):
 13     name = models.CharField(max_length=64,unique=True)
 14
 15     def __str__(self):
 16         return self.name
 17
 18 class Host(models.Model):
 19     """存储所有主机"""
 20     hostname = models.CharField(max_length=64)
 21     ip_addr = models.GenericIPAddressField(unique=True)
 22     port = models.PositiveSmallIntegerField(default=22)
 23     idc = models.ForeignKey("IDC")
 24
 25     enabled = models.BooleanField(default=True)
 26
 27     def __str__(self):
 28         return self.ip_addr
 29
 30
 31
 32 class HostGroup(models.Model):
 33     """主机组"""
 34     name = models.CharField(max_length=64, unique=True)
 35     bind_hosts  = models.ManyToManyField("BindHost")
 36     def __str__(self):
 37         return self.name
 38
 39
 40
 41 class RemoteUser(models.Model):
 42     """存储远程用户名密码"""
 43     username = models.CharField(max_length=64)
 44     auth_type_choices = ((0,'ssh/password'),(1,'ssh/key'))
 45     auth_type = models.SmallIntegerField(choices=auth_type_choices,default=0)
 46     password = models.CharField(max_length=128,blank=True,null=True)
 47
 48     #hosts = models.ManyToManyField("Host")
 49
 50     def __str__(self):
 51         return "%s(%s)%s" %( self.username,self.get_auth_type_display(),self.password)
 52
 53     class Meta:
 54         unique_together = ('username','auth_type','password')
 55
 56 class BindHost(models.Model):
 57     """绑定远程主机和远程用户的对应关系"""
 58     host = models.ForeignKey("Host")
 59     remote_user = models.ForeignKey("RemoteUser")
 60
 61     def __str__(self):
 62         return "%s -> %s" %(self.host,self.remote_user)
 63     class Meta:
 64         unique_together = ("host","remote_user")
 65
 66
 67
 68 class UserProfileManager(BaseUserManager):
 69     def create_user(self, email, name, password=None):
 70         """
 71         Creates and saves a User with the given email, date of
 72         birth and password.
 73         """
 74         if not email:
 75             raise ValueError('Users must have an email address')
 76
 77         user = self.model(
 78             email=self.normalize_email(email),
 79             name=name,
 80         )
 81
 82         user.set_password(password)
 83         user.save(using=self._db)
 84         return user
 85
 86     def create_superuser(self, email, name, password):
 87         """
 88         Creates and saves a superuser with the given email, date of
 89         birth and password.
 90         """
 91         user = self.create_user(
 92             email,
 93             password=password,
 94             name=name,
 95         )
 96         user.is_admin = True
 97         user.is_staff = True
 98         user.save(using=self._db)
 99         return user
100
101
102 class UserProfile(AbstractBaseUser,PermissionsMixin):
103     email = models.EmailField(
104         verbose_name='email address',
105         max_length=255,
106         unique=True,
107     )
108     name = models.CharField(max_length=64)
109     is_active = models.BooleanField(default=True)
110     is_admin = models.BooleanField(default=False)
111     is_staff = models.BooleanField(
112         ('staff status'),
113         default=False,
114         help_text=('Designates whether the user can log into this admin site.'),
115     )
116
117     bind_hosts = models.ManyToManyField("BindHost",blank=True)
118     host_groups = models.ManyToManyField("HostGroup",blank=True)
119
120     objects = UserProfileManager()
121
122     USERNAME_FIELD = 'email'
123     REQUIRED_FIELDS = ['name',]
124
125     def get_full_name(self):
126         # The user is identified by their email address
127         return self.email
128
129     def get_short_name(self):
130         # The user is identified by their email address
131         return self.email
132
133     def __str__(self):              # __unicode__ on Python 2
134         return self.email
135
136     def has_perm(self, perm, obj=None):
137         "Does the user have a specific permission?"
138         # Simplest possible answer: Yes, always
139         return True
140
141     def has_module_perms(self, app_label):
142         "Does the user have permissions to view the app `app_label`?"
143         # Simplest possible answer: Yes, always
144         return True
145
146
147
148
149 class Session(models.Model):
150     '''生成用户操作session id '''
151     user = models.ForeignKey('UserProfile')
152     bind_host = models.ForeignKey('BindHost')
153     tag = models.CharField(max_length=128,default='n/a')
154     closed = models.BooleanField(default=False)
155     cmd_count = models.IntegerField(default=0) #命令执行数量
156     stay_time = models.IntegerField(default=0, help_text="每次刷新自动计算停留时间",verbose_name="停留时长(seconds)")
157     date = models.DateTimeField(auto_now_add=True)
158
159     def __str__(self):
160         return '<id:%s user:%s bind_host:%s>' % (self.id,self.user.email,self.bind_host.host)
161     class Meta:
162         verbose_name = '审计日志'
163         verbose_name_plural = '审计日志'
164
165
166
167 class Task(models.Model):
168     """批量任务记录表"""
169     user = models.ForeignKey("UserProfile")
170     task_type_choices = ((0,'cmd'),(1,'file_transfer'))
171     task_type = models.SmallIntegerField(choices=task_type_choices)
172     content = models.TextField(verbose_name="任务内容")
173     #hosts = models.ManyToManyField("BindHost")
174     date  = models.DateTimeField(auto_now_add=True)
175
176     def __str__(self):
177         return "%s %s" %(self.task_type,self.content)
178
179
180 class TaskLogDetail(models.Model):
181     task = models.ForeignKey("Task")
182     bind_host = models.ForeignKey("BindHost")
183     result = models.TextField()
184
185     status_choices = ((0,'success'),(1,'failed'),(2,'init'))
186     status = models.SmallIntegerField(choices=status_choices)
187
188     start_date = models.DateTimeField(auto_now_add=True)
189     end_date = models.DateTimeField(blank=True,null=True)
190
191
192     def __str__(self):
193         return "%s %s" %(self.bind_host,self.status)

models

3、views

from django.shortcuts import render,redirect,HttpResponse
from django.contrib.auth.decorators import login_required
from django.contrib.auth import authenticate,logout,login
from  django.conf import settings
import os,re,json
from web import models
from backend.task_manager import  MultiTaskMangerfrom backend import audit
# Create your views here.def json_date_handler(obj):if hasattr(obj, 'isoformat'):return obj.strftime("%Y-%m-%d %T")@login_required
def dashboard(request):return render(request,'index.html')def acc_login(request):error_msg = ''if request.method == "POST":username = request.POST.get('username')password = request.POST.get('password')user = authenticate(username=username,password=password)if user:login(request,user)return redirect("/")else:error_msg = "Wrong username or password!"return render(request,"login.html",{'error_msg':error_msg})def acc_logout(request):logout(request)return redirect("/login/")@login_required
def webssh(request):return render(request,'web_ssh.html')@login_required
def user_audit(request):log_dirs = os.listdir(settings.AUDIT_LOG_DIR)return render(request,'user_audit.html',locals())@login_required
def audit_log_date(request,log_date):log_date_path = "%s/%s" %(settings.AUDIT_LOG_DIR,log_date)log_file_dirs = os.listdir(log_date_path)session_ids = [re.search("\d+",i).group() for i in log_file_dirs ]session_objs = models.Session.objects.filter(id__in=session_ids)return render(request, 'user_audit_file_list.html', locals())@login_required
def multitask_cmd(request):return render(request,"multitask_cmd.html")@login_required
def multitask_file_transfer(request):return render(request,'multitask_file_transfer.html')@login_required
def multitask_result(request):task_id = request.GET.get('task_id')task_obj = models.Task.objects.get(id=task_id)task_log_results = list(task_obj.tasklogdetail_set.values('id', 'result','status','start_date','end_date'))return  HttpResponse(json.dumps(task_log_results,default=json_date_handler))@login_required
def multitask(request):print("--->",request.POST)task_data = json.loads(request.POST.get('task_data'))print("--->selcted hosts",task_data)task_obj= MultiTaskManger(request)selected_hosts = list(task_obj.task.tasklogdetail_set.all().values('id', 'bind_host__host__ip_addr','bind_host__host__hostname', 'bind_host__remote_user__username'))return HttpResponse(json.dumps({'task_id':task_obj.task.id,'selected_hosts':selected_hosts}))@login_required
def audit_log_detail(request,log_date,session_id):log_date_path = "%s/%s" % (settings.AUDIT_LOG_DIR, log_date)log_file_path = "%s/session_%s.log" %(log_date_path,session_id)log_parser = audit.AuditLogHandler(log_file_path)cmd_list = log_parser.parse()return render(request,"user_audit_detail.html",locals())

五、测试截图

1、执行一条命令

1、web端

2、admin后台

2、执行多条命令

1、web前端

2、admin后台

4、连接不上的命令截图

连接不上直接排除timeout

3、后台触发一条命令

1、后台触发创建

2、控制台截图

3、admin后台截图

4、执行结果前端web显示

1、任务结果前端显示hostid

2、任务结果限制执行结果

3、超时处理

4、机器连接不通

5、超时状态数字变化

6、执行成功状态变化

转载于:https://www.cnblogs.com/luoahong/p/9501791.html

主机管理+堡垒机系统开发:前端批量命令结果(十二)相关推荐

  1. 主机管理+堡垒机系统开发

    本节内容 需求讨论 构架设计 表结构设计 程序开发 1.需求讨论 实现对用户的权限管理,能访问哪些机器,在被访问的机器上有哪些权限 实现可以通过web页面对指定主机列表 进行 批量发布命令.文件 实现 ...

  2. Teleport 简易堡垒机系统

    文章目录 简介 开源协议 界面展示 功能概述 特点 极易部署 安全增强 单点登录 按需授权 运维审计 功能 登录 登录方式 忘记密码 资产管理 用户管理 运维 审计 系统管理 客户端 技术选型 支持的 ...

  3. java 堡垒机_开源堡垒机系统Teleport部署教程

    认识Teleport 在开源堡垒机领域, 很多人都知道jumpserver, 但是jumpserver安装相对较复杂, 新手容易出现各种坑. 在这里介绍一款简单易用的开源堡垒机系统: Teleport ...

  4. java 保垒机telnet,开源堡垒机系统Teleport

    一. teleport简介 Teleport是一款简单易用的堡垒机系统,具有小巧.易用的特点,支持 RDP/SSH/SFTP/Telnet 协议的远程连接和审计管理. Teleport由两大部分构成: ...

  5. JavaWeb开发 前端语言:jQuery(二)属性操作、DOM的增删改、CSS样式操作、动画、事件操作

    JavaWeb开发 前端语言:jQuery(二) 1.jQuery的属性操作 2.jQuery练习:使用jQuery完成全选.全不选.反选和提交功能 3.DOM的增删改 3.1 DOM的增操作 3.1 ...

  6. libGDX游戏开发之打包游戏(十二)

    libGDX游戏开发之打包游戏(十二) libGDX系列,游戏开发有unity3D巴拉巴拉的,为啥还用java开发?因为我是Java程序员emm-国内用libgdx比较少,多数情况需要去官网和goog ...

  7. php开源堡垒机,开源堡垒机在开发环境中的使用方案-麒麟开源堡垒机

    一.部署说明: 开发环境主要使用开发人员的PC或笔记本终端进行开发,开发完成后,将代码交付相应的负责人,负责人编译测试后,将代码上传到CVS备份,将程序上传到生产环境使用.这种管理模式主要存在如下问题 ...

  8. 共享纸巾机系统开发,关于Switch的使用

    官方Switch教程方法: switch ($x) { case 1:echo "Number 1";break; case 2:echo "Number 2" ...

  9. qnx的汽车全液晶仪表-基于qnx系统的汽车仪表-车机系统开发

    如果你认为本系列文章对你有所帮助,请大家有钱的捧个钱场,点击此处赞助,赞助额0.1元起步,多少随意 声明:本文只用于个人学习交流,若不慎造成侵权,请及时联系我,立即予以改正 锋影 e-mail:174 ...

  10. 软件工程管理之《系统开发方法与项目生命周期的矛盾冲突》

    各位读者大家好,由于本文章是我在闲暇时间来迭代补充编辑的,并不是一次性编辑完成,如果影响大家的阅读感受,尽请大家谅解!!!  >>第一章:项目管理者情况 很高兴能与大家一起分享及探讨关于软 ...

最新文章

  1. NSIS 打包.net2.0
  2. c语言memset清空指向数组的指针_C语言中数组和指针的关系
  3. C++之explicit关键字使用总结
  4. 自适应滤波实例之系统逆辨识(以及系统零极点对逆辨识效果的影响分析)
  5. LeetCode 1953. 你可以工作的最大周数
  6. 文件共享存储主备实时热备实现方案
  7. Flex3 CRUD 与Java后台交互 完整Demo
  8. nginx 配置upstream实现负载均衡
  9. Linux下数学(科学)软件简介(一)
  10. Linux 安装 VMware Player
  11. QT 字符乱码的原因
  12. c语言null是什么意思,c语言null什么意思?
  13. cesium加载S3M白膜,通过分层设色实现渐变效果,设置点光源
  14. 《CCNet:Criss-Cross Attention for Semantic Segmentation》论文笔记
  15. 2019网易校招(1星) 俄罗斯方块
  16. 基于Maven profile配置
  17. 波兰计算机专业大学排名,波兰留学大学排名
  18. Android自定义view之网易云推荐歌单界面
  19. IOCP之accept、AcceptEx、WSAAccept的区别 .
  20. libigl第五章-参数化

热门文章

  1. oracle试图怎么使用,oracle 视图的介绍和使用
  2. matlab gui编写计算器,怎样用MATLAB中的GUI做一个简单计算器
  3. 课程《设计模式之美》笔记之关于java四大特性
  4. 前后端分离项目如何部署_不用Docker前后端分离项目如何快速部署
  5. 利用定时器中断方式控制led灯的闪烁速度_实验四 LED点阵
  6. [渝粤教育] 西南科技大学 微机原理与应用 在线考试复习资料(2)
  7. 机器学习系列(九)【最大熵模型】
  8. 迁移学习——数据不够的情况下训练深度学习模型
  9. 求解偏微分方程开源有限元软件deal.II学习--Step 9
  10. 中国政法大学政治与公共管理学院丛日云教授在毕业典礼上的演讲在网络上暴红,