Skip to content

Commit 9c20493

Browse files
committed
scan&login execution
1 parent 371b1eb commit 9c20493

File tree

7 files changed

+168
-10
lines changed

7 files changed

+168
-10
lines changed

apps/cmdb/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
default_app_config = 'cmdb.apps.CmdbConfig'

apps/cmdb/apps.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@
22

33

44
class CmdbConfig(AppConfig):
5-
name = 'cmdb'
5+
name = 'cmdb'
6+
7+
def ready(self):
8+
from .signals import auto_delete_file

apps/cmdb/models.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import os
21
from datetime import datetime
32

43
from django.db import models
54
from django.contrib.auth import get_user_model
6-
from django.dispatch import receiver
5+
6+
from simple_history.models import HistoricalRecords
77

88
User = get_user_model()
99

@@ -99,20 +99,24 @@ class DeviceInfo(AbstractMode, DeviceAbstract, TimeAbstract):
9999
buyDate = models.DateField(default=datetime.now, verbose_name="购买日期")
100100
warrantyDate = models.DateField(default=datetime.now, verbose_name="到保日期")
101101
desc = models.TextField(blank=True, default='', verbose_name='备注信息')
102+
changed_by = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL)
103+
history = HistoricalRecords(excluded_fields=['add_time', 'modify_time'])
102104

103105
class Meta:
104106
verbose_name = '设备信息'
105107
verbose_name_plural = verbose_name
106108

109+
@property
110+
def _history_user(self):
111+
return self.changed_by
112+
113+
@_history_user.setter
114+
def _history_user(self, value):
115+
self.changed_by = value
116+
107117

108118
class DeviceFile(TimeAbstract):
109119
device = models.ForeignKey('DeviceInfo', blank=True, null=True, on_delete=models.SET_NULL, verbose_name='设备')
110120
file_content = models.FileField(upload_to="asset_file/%Y/%m", null=True, blank=True, verbose_name="资产文件")
111121
upload_user = models.CharField(max_length=20, verbose_name="上传人")
112122

113-
114-
@receiver(models.signals.post_delete, sender=DeviceFile)
115-
def auto_delete_file(sender, instance, **kwargs):
116-
if instance.file_content:
117-
if os.path.isfile(instance.file_content.path):
118-
os.remove(instance.file_content.path)

apps/cmdb/signals.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import os
2+
3+
from django.dispatch import receiver
4+
from django.db.models.signals import post_delete
5+
6+
from .models import DeviceFile
7+
8+
9+
@receiver(post_delete, sender=DeviceFile)
10+
def auto_delete_file(sender, instance, **kwargs):
11+
if instance.file_content:
12+
if os.path.isfile(instance.file_content.path):
13+
os.remove(instance.file_content.path)

apps/utils/sandbox_utils.py

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
import yaml
1010
import logging
11+
import nmap
12+
import paramiko
1113

1214
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sandboxMP.settings')
1315
error_logger = logging.getLogger('sandbox_error')
@@ -72,3 +74,136 @@ def get_net_address(self):
7274
"""
7375
key = ['hosts', 'net_address']
7476
return self.get_conf_content(*key)
77+
78+
79+
class SandboxScan(ConfigFileMixin):
80+
81+
def basic_scan(self):
82+
"""
83+
Use ICMP discovery online hosts and return online hosts.
84+
"""
85+
hosts = self.get_net_address()
86+
nm = nmap.PortScanner()
87+
nm.scan(hosts=hosts, arguments='-n -sP -PE')
88+
online_hosts = nm.all_hosts()
89+
return online_hosts
90+
91+
def os_scan(self):
92+
"""
93+
Get the system type by nmap scan and return hosts list with os type.
94+
"""
95+
hosts = self.get_net_address()
96+
nm = nmap.PortScanner()
97+
nm.scan(hosts=hosts, arguments='-n sS -O')
98+
online_hosts = []
99+
for host in nm.all_hosts():
100+
try:
101+
os_type = nm[host]['osmatch'][0]['osclass'][0]['osfamily']
102+
except Exception:
103+
os_type = 'unknown'
104+
host_dict = {'host': host, 'os': os_type}
105+
online_hosts.append(host_dict)
106+
return online_hosts
107+
108+
def get_net_address(self):
109+
"""
110+
Return the hosts that will be used to scan.
111+
Subclasses can override this to return any hosts.`
112+
"""
113+
hosts_list = super().get_net_address()
114+
hosts = ' '.join(str(i) for i in hosts_list)
115+
return hosts
116+
117+
118+
class LoginExecution(ConfigFileMixin):
119+
120+
def login_execution(self, auth_type='password', **kwargs):
121+
"""
122+
Support two authentication modes: password or private_key, and auth_type default is password.
123+
"""
124+
ssh = paramiko.SSHClient()
125+
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
126+
try:
127+
if auth_type == 'password':
128+
ssh.connect(
129+
kwargs['hostname'],
130+
kwargs['port'],
131+
kwargs['username'],
132+
kwargs['password'],
133+
timeout=3,
134+
)
135+
kwargs['auth_type'] = 'password'
136+
elif auth_type == 'private_key':
137+
kwargs['auth_type'] = 'private_key'
138+
private_key = paramiko.RSAKey.from_private_key_file(kwargs['private_key'])
139+
ssh.connect(
140+
kwargs['hostname'],
141+
kwargs['port'],
142+
kwargs['username'],
143+
private_key,
144+
timeout=3,
145+
)
146+
kwargs['status'] = 'succeed'
147+
kwargs['error_message'] = ''
148+
commands = self.get_commands()
149+
for key, value in commands.items():
150+
stdin, stdout, stderr = ssh.exec_command(value, timeout=5)
151+
result = str(stdout.read()).strip('b').strip("'").strip('\\n')
152+
kwargs[key] = result
153+
except Exception as e:
154+
msg = '%(exc)s hostname %(hostname)s' % {
155+
'exc': e,
156+
'hostname': kwargs['hostname']
157+
}
158+
error_logger.error(msg)
159+
kwargs['status'] = 'failed'
160+
kwargs['error_message'] = str(e)
161+
return kwargs
162+
163+
def password_login_execution(self, **kwargs):
164+
"""
165+
Login to the remote system with a password.
166+
Kwargs is a dict containing hostname, port, username and password.
167+
Example: kwargs = {'hostname': '172.16.3.101', 'port': 22, 'username': 'root', 'password': 'paw123'}
168+
"""
169+
return self.login_execution(**kwargs)
170+
171+
def private_key_login_execution(self, **kwargs):
172+
"""
173+
Login to the remote system with a private_key.
174+
Kwargs is a dict containing hostname, port, username and private key.
175+
Example:kwargs = {'hostname': '172.16.3.101', 'port': 22, 'username': 'root', 'private_key': '/root/.ssh/id_rsa'}
176+
"""
177+
return self.login_execution(auth_type='private_key', **kwargs)
178+
179+
def get_auth_type(self):
180+
key = ['hosts', 'auth_type']
181+
return self.get_conf_content(*key)
182+
183+
def get_ssh_username(self):
184+
key = ['hosts', 'ssh_username']
185+
return self.get_conf_content(*key)
186+
187+
def get_ssh_port(self):
188+
key = ['hosts', 'ssh_port']
189+
return self.get_conf_content(*key)
190+
191+
def get_ssh_password(self):
192+
key = ['hosts', 'ssh_password']
193+
return self.get_conf_content(*key)
194+
195+
def get_ssh_private_key(self):
196+
key = ['hosts', 'ssh_private_key']
197+
return self.get_conf_content(*key)
198+
199+
def get_email(self):
200+
key = ['hosts', 'email']
201+
return self.get_conf_content(*key)
202+
203+
def get_send_email(self):
204+
key = ['hosts', 'send_email']
205+
return self.get_conf_content(*key)
206+
207+
def get_scan_type(self):
208+
key = ['hosts', 'scan_type']
209+
return self.get_conf_content(*key)

requirements/pro.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ python-nmap==0.6.1
88
redis==3.0.1
99
pymongo==3.7.1
1010
paramiko==2.4.2
11-
pycrypto==2.6.1
11+
django-simple-history==2.6.0
1212
celery==4.2.1
1313
celery-once==2.0.0
1414
flower==0.9.2

sandboxMP/settings.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
'django.contrib.sessions',
4040
'django.contrib.messages',
4141
'django.contrib.staticfiles',
42+
'simple_history',
4243
'system',
4344
'cmdb',
4445
]
@@ -53,6 +54,7 @@
5354
'django.middleware.clickjacking.XFrameOptionsMiddleware',
5455
'apps.system.middleware.MenuCollection',
5556
'apps.system.middleware.RbacMiddleware',
57+
'simple_history.middleware.HistoryRequestMiddleware',
5658
]
5759

5860
ROOT_URLCONF = 'sandboxMP.urls'

0 commit comments

Comments
 (0)