├── .gitignore ├── README.md ├── manage.py ├── requirements.txt ├── static └── jquery-1.12.4.js ├── templates └── index.html ├── wdpy ├── __init__.py ├── settings.py ├── urls.py └── wsgi.py ├── websocket ├── __init__.py ├── admin.py ├── apps.py ├── migrations │ └── __init__.py ├── models.py ├── tests.py └── views.py └── 效果图 ├── 安装软件.gif └── 执行脚本.gif /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 说明 2 | websocket+Django+python+paramiko实现web页面执行命令并实时输出 3 | 4 | ## 环境依赖 5 | 6 | | Project | Status | Description | 7 | |---------|--------|-------------| 8 | | python | 3.5.4 | 在这个版本以及以上都课可以 | 9 | | django | 2.1.4 | 大于2.0,小于2.1.5 | 10 | | paramiko | 2.4.2 | 无 | 11 | 12 | ## 注意事项 13 | 14 | django版本不能是2.1.5,使用websocket,谷歌浏览器会报错 15 | 16 | `WebSocket connection to 'ws://127.0.01:8000/echo_once/' failed: Error during WebSocket handshake: Unexpected response code: 400` 17 | 18 | ## 安装依赖 19 | `pip3 install -r requirements.txt` 20 | 21 | 或者 22 | 23 | `pip3 install paramiko dwebsocket django==2.1.4` 24 | 25 | ## 运行方式 26 | 27 | 使用Pycharm直接运行即可 28 | 29 | 或者使用命令 30 | `python manage.py runserver` 31 | 32 | 33 | ## 效果图 34 | 35 | 执行脚本 36 | 37 | ![Image text](https://github.com/py3study/wdpy/blob/master/%E6%95%88%E6%9E%9C%E5%9B%BE/%E6%89%A7%E8%A1%8C%E8%84%9A%E6%9C%AC.gif) 38 | 39 | 安装软件 40 | 41 | ![Image text](https://github.com/py3study/wdpy/blob/master/%E6%95%88%E6%9E%9C%E5%9B%BE/%E5%AE%89%E8%A3%85%E8%BD%AF%E4%BB%B6.gif) 42 | 43 | Copyright (c) 2018-present, xiao You -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "wdpy.settings") 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError as exc: 10 | raise ImportError( 11 | "Couldn't import Django. Are you sure it's installed and " 12 | "available on your PYTHONPATH environment variable? Did you " 13 | "forget to activate a virtual environment?" 14 | ) from exc 15 | execute_from_command_line(sys.argv) 16 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Django==2.1.4 2 | dwebsocket==0.5.10 3 | paramiko==2.4.2 4 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CMDB系统 6 | 7 | 27 | 28 | 29 | {#
#} 30 | 33 |

脚本执行结果:

34 |
35 |
36 |
37 | 38 | -------------------------------------------------------------------------------- /wdpy/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py3study/wdpy/ac6d4928f122a495cf00962554a683e2cd184670/wdpy/__init__.py -------------------------------------------------------------------------------- /wdpy/settings.py: -------------------------------------------------------------------------------- 1 | """ 2 | Django settings for wdpy project. 3 | 4 | Generated by 'django-admin startproject' using Django 2.0.2. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.0/topics/settings/ 8 | 9 | For the full list of settings and their values, see 10 | https://docs.djangoproject.com/en/2.0/ref/settings/ 11 | """ 12 | 13 | import os 14 | 15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...) 16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 17 | 18 | 19 | # Quick-start development settings - unsuitable for production 20 | # See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/ 21 | 22 | # SECURITY WARNING: keep the secret key used in production secret! 23 | SECRET_KEY = '^1*)==*l(kt=+!#h*ja)+q&@5jav5wtf+dj!d9op!%)^+z_r%%' 24 | 25 | # SECURITY WARNING: don't run with debug turned on in production! 26 | DEBUG = True 27 | 28 | ALLOWED_HOSTS = [] 29 | 30 | 31 | # Application definition 32 | 33 | INSTALLED_APPS = [ 34 | 'django.contrib.admin', 35 | 'django.contrib.auth', 36 | 'django.contrib.contenttypes', 37 | 'django.contrib.sessions', 38 | 'django.contrib.messages', 39 | 'django.contrib.staticfiles', 40 | 'websocket.apps.WebsocketConfig', 41 | ] 42 | 43 | MIDDLEWARE = [ 44 | 'django.middleware.security.SecurityMiddleware', 45 | 'django.contrib.sessions.middleware.SessionMiddleware', 46 | 'django.middleware.common.CommonMiddleware', 47 | 'django.middleware.csrf.CsrfViewMiddleware', 48 | 'django.contrib.auth.middleware.AuthenticationMiddleware', 49 | 'django.contrib.messages.middleware.MessageMiddleware', 50 | 'django.middleware.clickjacking.XFrameOptionsMiddleware', 51 | ] 52 | 53 | ROOT_URLCONF = 'wdpy.urls' 54 | 55 | TEMPLATES = [ 56 | { 57 | 'BACKEND': 'django.template.backends.django.DjangoTemplates', 58 | 'DIRS': [os.path.join(BASE_DIR, 'templates')] 59 | , 60 | 'APP_DIRS': True, 61 | 'OPTIONS': { 62 | 'context_processors': [ 63 | 'django.template.context_processors.debug', 64 | 'django.template.context_processors.request', 65 | 'django.contrib.auth.context_processors.auth', 66 | 'django.contrib.messages.context_processors.messages', 67 | ], 68 | }, 69 | }, 70 | ] 71 | 72 | WSGI_APPLICATION = 'wdpy.wsgi.application' 73 | 74 | 75 | # Database 76 | # https://docs.djangoproject.com/en/2.0/ref/settings/#databases 77 | 78 | DATABASES = { 79 | 'default': { 80 | 'ENGINE': 'django.db.backends.sqlite3', 81 | 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 82 | } 83 | } 84 | 85 | 86 | # Password validation 87 | # https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators 88 | 89 | AUTH_PASSWORD_VALIDATORS = [ 90 | { 91 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 92 | }, 93 | { 94 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 95 | }, 96 | { 97 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 98 | }, 99 | { 100 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 101 | }, 102 | ] 103 | 104 | 105 | # Internationalization 106 | # https://docs.djangoproject.com/en/2.0/topics/i18n/ 107 | 108 | LANGUAGE_CODE = 'en-us' 109 | 110 | TIME_ZONE = 'UTC' 111 | 112 | USE_I18N = True 113 | 114 | USE_L10N = True 115 | 116 | USE_TZ = True 117 | 118 | 119 | # Static files (CSS, JavaScript, Images) 120 | # https://docs.djangoproject.com/en/2.0/howto/static-files/ 121 | 122 | STATIC_URL = '/static/' 123 | STATICFILES_DIRS = ( 124 | os.path.join(BASE_DIR,"static"), 125 | ) -------------------------------------------------------------------------------- /wdpy/urls.py: -------------------------------------------------------------------------------- 1 | """wdpy URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/2.0/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import path 18 | from websocket import views 19 | 20 | urlpatterns = [ 21 | path('admin/', admin.site.urls), 22 | path('echo_once/', views.echo_once), 23 | ] -------------------------------------------------------------------------------- /wdpy/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for wdpy project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/2.0/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "wdpy.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /websocket/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py3study/wdpy/ac6d4928f122a495cf00962554a683e2cd184670/websocket/__init__.py -------------------------------------------------------------------------------- /websocket/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /websocket/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class WebsocketConfig(AppConfig): 5 | name = 'websocket' 6 | -------------------------------------------------------------------------------- /websocket/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py3study/wdpy/ac6d4928f122a495cf00962554a683e2cd184670/websocket/migrations/__init__.py -------------------------------------------------------------------------------- /websocket/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /websocket/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /websocket/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | from dwebsocket.decorators import accept_websocket, require_websocket 3 | from django.http import HttpResponse 4 | import paramiko 5 | 6 | 7 | # def exec_command(comm): 8 | # hostname = '192.168.0.162' 9 | # username = 'root' 10 | # password = 'root' 11 | # 12 | # ssh = paramiko.SSHClient() 13 | # ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 14 | # ssh.connect(hostname=hostname, username=username, password=password) 15 | # stdin, stdout, stderr = ssh.exec_command(comm,get_pty=True) 16 | # result = stdout.read() 17 | # ssh.close() 18 | # yield result 19 | 20 | 21 | @accept_websocket 22 | def echo_once(request): 23 | if not request.is_websocket(): # 判断是不是websocket连接 24 | try: # 如果是普通的http方法 25 | message = request.GET['message'] 26 | return HttpResponse(message) 27 | except: 28 | return render(request, 'index.html') 29 | else: 30 | for message in request.websocket: 31 | message = message.decode('utf-8') # 接收前端发来的数据 32 | print(message) 33 | if message == 'backup_all':#这里根据web页面获取的值进行对应的操作 34 | command = 'bash /opt/test.sh'#这里是要执行的命令或者脚本 35 | 36 | # 远程连接服务器 37 | hostname = '192.168.0.162' 38 | username = 'root' 39 | password = 'root' 40 | 41 | ssh = paramiko.SSHClient() 42 | ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 43 | ssh.connect(hostname=hostname, username=username, password=password) 44 | # 务必要加上get_pty=True,否则执行命令会没有权限 45 | stdin, stdout, stderr = ssh.exec_command(command, get_pty=True) 46 | # result = stdout.read() 47 | # 循环发送消息给前端页面 48 | while True: 49 | nextline = stdout.readline().strip() # 读取脚本输出内容 50 | # print(nextline.strip()) 51 | request.websocket.send(nextline) # 发送消息到客户端 52 | # 判断消息为空时,退出循环 53 | if not nextline: 54 | break 55 | 56 | ssh.close() # 关闭ssh连接 57 | else: 58 | request.websocket.send('小样儿,没权限!!!'.encode('utf-8')) -------------------------------------------------------------------------------- /效果图/安装软件.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py3study/wdpy/ac6d4928f122a495cf00962554a683e2cd184670/效果图/安装软件.gif -------------------------------------------------------------------------------- /效果图/执行脚本.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/py3study/wdpy/ac6d4928f122a495cf00962554a683e2cd184670/效果图/执行脚本.gif --------------------------------------------------------------------------------