├── .gitignore
├── README.md
├── agent
├── VERSION
├── base.xml
├── client.py
├── constants.py
├── disk.xml
├── host.py
├── log.py
├── task.py
├── test
│ ├── 1.xml
│ ├── 111.qcow2
│ ├── 2.xml
│ ├── build_host_hw.py
│ ├── build_host_status.py
│ ├── build_vm_conf.py
│ ├── build_vm_status.py
│ ├── cdrom_xml.py
│ ├── cds.xml
│ ├── cds222.xml
│ ├── disk_xml.py
│ ├── file1.py
│ ├── hd_xml.py
│ ├── host_getMaxVcpus.py
│ ├── host_get_file_list.py
│ ├── host_get_hw_info.py
│ ├── host_get_iso.py
│ ├── host_get_resource.py
│ ├── host_get_sw_info.py
│ ├── host_nodeinfo.py
│ ├── path.py
│ ├── prepare_img.py
│ ├── snapshot_xml.py
│ ├── task_action.py
│ ├── task_create_snapshot.py
│ ├── task_define.py
│ ├── task_delete.py
│ ├── task_delete_snapshot.py
│ ├── task_download.py
│ ├── task_edit.py
│ ├── task_report.py
│ ├── task_resume_snapshot.py
│ ├── task_set_ip.py
│ ├── test.py
│ ├── threadpool_test.py
│ ├── vm_define.py
│ ├── vm_destroy.py
│ ├── vm_edit_conf.py
│ ├── vm_get_info.py
│ ├── vm_get_os_version.py
│ ├── vm_get_status.py
│ ├── vm_judge_exist.py
│ ├── vm_read_vm_file.py
│ ├── vm_shutdown.py
│ ├── vm_start.py
│ ├── vm_start_from_cdrom.py
│ ├── vm_undefine.py
│ ├── vm_write_vm_file.py
│ └── xingyu.xml
├── vm.py
├── vpe.conf
└── xml_api.py
├── docs
├── libvirt-1.0-Libvirt_Application_Development_Guide_Using_Python-en-US.pdf
├── 接口设计文档.txt
├── 数据库设计.png
└── 环境部署说明.txt
├── screenshots
├── 任务管理.jpg
├── 添加镜像模板.jpg
├── 登录页.jpg
├── 虚拟机列表.jpg
├── 虚拟机快照管理.jpg
├── 虚拟机总览.jpg
├── 虚拟机配置.jpg
├── 设备列表页.jpg
└── 设备总览.jpg
└── web
├── api
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│ ├── 0001_initial.py
│ ├── 0002_auto_20160608_1532.py
│ ├── 0003_auto_20160608_1605.py
│ └── __init__.py
├── models.py
├── tests.py
└── views.py
├── manage.py
├── server
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│ ├── 0001_initial.py
│ └── __init__.py
├── models.py
├── tests.py
└── views.py
├── templates
├── 444.html
├── api_error.html
├── base.html
├── basic_modal.html
├── basic_task_modal.html
├── create_ins_modal.html
├── login.html
├── server
│ ├── instances.html
│ ├── logs.html
│ ├── modal_add_iostemp.html
│ ├── modal_add_vmfile.html
│ ├── overview.html
│ ├── packages.html
│ ├── server_info.html
│ ├── server_list.html
│ ├── setting.html
│ ├── tasks-all.html
│ └── tasks.html
└── side_base.html
└── webkvmmgr
├── __init__.py
├── settings.py
├── static
├── css
│ ├── bootstrap-switch.min.css
│ ├── common.css
│ ├── instance.css
│ ├── login.css
│ ├── server.css
│ └── tasks.css
├── images
│ ├── avatar.svg
│ ├── bg.png
│ ├── favicon.ico
│ ├── logo.png
│ ├── logofx.jpg
│ ├── logofx.png
│ ├── main.png
│ ├── password.svg
│ └── username.svg
└── js
│ ├── bootstrap-switch.min.js
│ ├── common.js
│ ├── echarts.min.js
│ ├── instance.js
│ ├── login.js
│ └── server.js
├── urls.py
└── wsgi.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Python template
3 | # Byte-compiled / optimized / DLL files
4 | __pycache__/
5 | *.py[cod]
6 | *$py.class
7 |
8 | # C extensions
9 | *.so
10 |
11 | # Distribution / packaging
12 | .Python
13 | env/
14 | build/
15 | develop-eggs/
16 | dist/
17 | downloads/
18 | eggs/
19 | .eggs/
20 | lib/
21 | lib64/
22 | parts/
23 | sdist/
24 | var/
25 | *.egg-info/
26 | .installed.cfg
27 | *.egg
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .coverage
43 | .coverage.*
44 | .cache
45 | nosetests.xml
46 | coverage.xml
47 | *,cover
48 | .hypothesis/
49 |
50 | # Translations
51 | *.mo
52 | *.pot
53 |
54 | # Django stuff:
55 | *.log
56 | local_settings.py
57 |
58 | # Flask stuff:
59 | instance/
60 | .webassets-cache
61 |
62 | # Scrapy stuff:
63 | .scrapy
64 |
65 | # Sphinx documentation
66 | docs/_build/
67 |
68 | # PyBuilder
69 | target/
70 |
71 | # IPython Notebook
72 | .ipynb_checkpoints
73 |
74 | # pyenv
75 | .python-version
76 |
77 | # celery beat schedule file
78 | celerybeat-schedule
79 |
80 | # dotenv
81 | .env
82 |
83 | # virtualenv
84 | venv/
85 | ENV/
86 |
87 | # Spyder project settings
88 | .spyderproject
89 |
90 | # Rope project settings
91 | .ropeproject
92 |
93 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # webkvmmgr
2 | KVM Manager with Django
3 |
4 | ## Demo video
5 | [http://v.qq.com/page/w/7/1/w0313ztcu71.html](http://v.qq.com/page/w/7/1/w0313ztcu71.html)
6 |
7 | ## Requirements
8 | ### 宿主机
9 | 1. host目前选择版本: centos6.x 或 centos7
10 |
11 | 2. Host安装包:
12 |
13 | 1) kvm相关包:
14 | yum install qemu-kvm libvirt libvirt-python
15 |
16 | 2) python依赖包:
17 | requests、threadpool
18 |
19 | 3) 其它rpm包:
20 | util-linux
21 |
22 | 3. Disk配置:
23 |
24 | 1) 指定1块硬盘,例如/dev/sda,用来存放vm的系统盘;
25 |
26 | 2) 格式化,并挂载到/img/os目录;
27 |
28 | 3) 指定剩下的N-1块硬盘,用来存放vm的数据盘;(如果硬盘做了raid,则意味着,这个raid盘,用来存放vm的数据盘)
29 |
30 | 4) 格式化,并挂载到/img/dataN目录;
31 |
32 | 举例:
33 | 例如一个host有5块盘,sda/sdb/sdc/sdd/sde,则:
34 |
35 | 1) 选择sda用来存放vm的系统盘;
36 |
37 | 2) 格式化并挂载:
38 | mkfs.ext4 /dev/sda && mount /dev/sda /img/os
39 |
40 | 3) 选择sdb/sdc/sdd/sde,用来存放vm的数据盘;
41 |
42 | 4) 格式化并挂载:
43 | ```
44 | mkfs.ext4 /dev/sdb && mount /dev/sdb /img/data1
45 | mkfs.ext4 /dev/sdc && mount /dev/sdc /img/data2
46 | mkfs.ext4 /dev/sdd && mount /dev/sdd /img/data3
47 | mkfs.ext4 /dev/sde && mount /dev/sde /img/data4
48 | ```
49 |
50 | 4. net配置:
51 | 创建一个名叫ovirtmgmt的网桥
52 |
53 | ### 虚拟机
54 | 1. 安装rpm包qemu-guest-agent:
55 | yum install qemu-guest-agent
56 |
57 | 2. 添加开机自启动程序:
58 | killall qemu-ga
59 | nohup qemu-ga -p /dev/virtio-ports/org.qemu.guest_agent.0 &
60 |
61 | ## Screenshot
62 |
63 | * 登录页
64 |
65 |
66 |
67 | * 设备列表页
68 |
69 |
70 |
71 | * 设备总览
72 |
73 |
74 |
75 | * 虚拟机列表
76 |
77 |
78 |
79 | * 虚拟机总览
80 |
81 |
82 |
83 | * 虚拟机快照管理
84 |
85 |
86 |
87 | * 虚拟机配置
88 |
89 |
90 |
91 |
92 | * 添加镜像模板
93 |
94 |
95 |
96 | * 任务管理
97 |
98 |
99 |
100 |
101 | ## Todo List
102 | * 重新组织agent代码, 现在代码还没有整理;
103 | * 完善文档;
--------------------------------------------------------------------------------
/agent/VERSION:
--------------------------------------------------------------------------------
1 | 1.0.0
2 |
--------------------------------------------------------------------------------
/agent/base.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 4
6 |
7 | hvm
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | destroy
17 | restart
18 | restart
19 |
20 | /usr/libexec/qemu-kvm
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/agent/client.py:
--------------------------------------------------------------------------------
1 | import requests
2 | from log import logger
3 | import json
4 | import datetime
5 | from vm import vm
6 | from host import vmmhost
7 | import libvirt
8 | import constants
9 | import Queue
10 | import time
11 | import os
12 |
13 | """
14 | url_up = 'http://192.168.1.136:8000/api/kvm'
15 | #headers = {'content-type': 'application/json'}
16 | payload = {'key1': 'value1', 'key2': 'value2'}
17 | r = requests.post(url_up, data=json.dumps(payload))
18 | """
19 |
20 | def get_now_str():
21 | return datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
22 |
23 | def build_vm_conf(sn, uri = "qemu:///system"):
24 |
25 | conn = None
26 | try:
27 | conn = libvirt.open(uri)
28 | except Exception, e:
29 | logger.exception(e)
30 |
31 | ret_dict = {}
32 | ret_dict['req'] = "vm.conf"
33 | ret_dict['sn'] = sn
34 |
35 | doms_info = []
36 | chost = vmmhost(sn, conn)
37 | now_time = get_now_str()
38 | for name in chost.get_vmlist():
39 | dom_info = {}
40 | dom_info['name'] = name
41 | dom_info['update_time'] = now_time
42 | dom_info['type'] = 0
43 | avm = vm(name)
44 | dom_info['os'] = avm.get_os_version() #todo: lsb_release -d
45 | dom_info['cpu_num'] = avm.get_cpu_num()
46 | dom_info['memory'] = avm.get_mem()
47 | dom_info['disk'] = avm.get_disk_info()
48 | dom_info['network'] = avm.get_net_info()
49 | snapshot_list = avm.get_snapshots()
50 | snapshot_list_info = []
51 | for item in snapshot_list:
52 | snap_item = {}
53 | snap_item['name'] = item
54 | snap_item['create_time'] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) #todo
55 | snap_item['comment'] = "xxxx"
56 | snapshot_list_info.append(snap_item)
57 | dom_info['snapshots'] = snapshot_list_info
58 |
59 | doms_info.append(dom_info)
60 |
61 | ret_dict['body'] = doms_info
62 | logger.debug('---------------------------------------------------')
63 | logger.debug(ret_dict)
64 |
65 | if conn:
66 | conn.close()
67 |
68 | return ret_dict
69 |
70 | def build_vm_status(sn, uri = "qemu:///system"):
71 |
72 | conn = None
73 | try:
74 | conn = libvirt.open(uri)
75 | except Exception, e:
76 | logger.exception(e)
77 |
78 | ret_dict = {}
79 | ret_dict['req'] = "vm.status"
80 | ret_dict['sn'] = sn
81 |
82 | doms_info = []
83 | chost = vmmhost(sn, conn)
84 | now_time = get_now_str()
85 | for name in chost.get_vmlist():
86 | print name
87 | dom_info = {}
88 | dom_info['name'] = name
89 | dom_info['update_time'] = now_time
90 |
91 | avm = vm(name)
92 | run_status = avm.get_status()
93 | dom_info['status'] = run_status['vm_status']
94 |
95 |
96 | if dom_info['status'] == constants.vm_status_running:
97 |
98 | vm_info = avm.get_info()
99 | dom_info['cpu_idle'] = vm_info['cpu_idle']
100 | dom_info['mem_usage'] = vm_info['mem_usage']
101 | dom_info['disk'] = [] #todo
102 | net_item = {}
103 | net_item['name'] = ""
104 | dom_info['net'] = avm._get_network_interfaces()
105 | else:
106 | dom_info['cpu_idle'] = 100.00
107 | dom_info['mem_usage'] = 0.00
108 | dom_info['disk'] = []
109 | dom_info['net'] = []
110 |
111 | doms_info.append(dom_info)
112 |
113 | ret_dict['body'] = doms_info
114 |
115 | logger.debug(ret_dict)
116 |
117 | if conn:
118 | conn.close()
119 |
120 | return ret_dict
121 |
122 | def build_host_hw(sn, uri = "qemu:///system"):
123 |
124 | conn = None
125 | try:
126 | conn = libvirt.open(uri)
127 | except Exception, e:
128 | logger.exception(e)
129 |
130 | ret_dict = {}
131 | ret_dict['req'] = "host.hw"
132 | ret_dict['sn'] = sn
133 |
134 | chost = vmmhost(sn, conn)
135 |
136 | ret_dict['body'] = [ chost.get_hw_info() ]
137 |
138 | if conn:
139 | conn.close()
140 |
141 | return ret_dict
142 |
143 | def build_host_status(sn, uri = "qemu:///system"):
144 |
145 | conn = None
146 | try:
147 | conn = libvirt.open(uri)
148 | except Exception, e:
149 | logger.exception(e)
150 |
151 | ret_dict = {}
152 | ret_dict['req'] = "host.status"
153 | ret_dict['sn'] = sn
154 |
155 | chost = vmmhost(sn, conn)
156 | host_info = chost.get_sw_info()
157 | host_info['name'] = chost.get_hostname()
158 | host_info['status'] = 1
159 | host_info['update_time'] = get_now_str()
160 | host_info['task'] = [] #todo
161 |
162 |
163 | host_info['mem_usage'] = chost.get_memory_usage()['mem_usage']
164 | host_info['cpu_idle'] = ("%.2f" % (100- float(chost.get_cpu_usage()['cpu_usage'])))
165 | host_info['disk'] = chost.get_disk_usage()
166 | host_info['net'] = chost.get_net_usage()
167 | #todo
168 | host_info['ip'] = str(chost.get_out_ip())
169 | host_info['disk_usage'] = 20 #%.2f
170 |
171 | #todo: filter files by 'iso/ISO'
172 | vm_files = []
173 | vm_file_item = {}
174 |
175 | for i in os.listdir(constants.iso_path):
176 | abs_path = os.path.join(constants.iso_path, i)
177 | if os.path.isfile(abs_path):
178 | vm_file_item={}
179 | vm_file_item['name'] = i
180 | vm_file_item['type'] = 0
181 | vm_file_item['size'] = os.path.getsize(abs_path)
182 | vm_file_item['path'] = constants.iso_path
183 | vm_files.append(vm_file_item)
184 |
185 | for i in os.listdir(constants.img_template_path):
186 | abs_path = os.path.join(constants.img_template_path, i)
187 | if os.path.isfile(abs_path):
188 | vm_file_item={}
189 | vm_file_item['name'] = i
190 | vm_file_item['type'] = 0
191 | vm_file_item['size'] = os.path.getsize(abs_path)
192 | vm_file_item['path'] = constants.img_template_path
193 | vm_files.append(vm_file_item)
194 |
195 | host_info['vm_files'] = vm_files
196 |
197 | ret_dict['body'] = [ host_info ]
198 |
199 | if conn:
200 | conn.close()
201 |
202 | logger.debug(ret_dict)
203 | return ret_dict
204 |
205 |
206 | def start():
207 | sn = 'CAS1000000000'
208 | try:
209 | payload = build_host_hw(sn)
210 | logger.debug(json.dumps(payload))
211 | r = requests.post(constants.url_status, data=json.dumps(payload))
212 | except Exception, e:
213 | logger.exception(e)
214 | while 1:
215 |
216 | try:
217 | payload = build_host_status(sn)
218 | r = requests.post(constants.url_status, data=json.dumps(payload))
219 | print r.status_code
220 |
221 | payload = build_vm_conf(sn)
222 | r = requests.post(constants.url_status, data=json.dumps(payload))
223 | print r.status_code
224 |
225 | payload = build_vm_status(sn)
226 | r = requests.post(constants.url_status, data=json.dumps(payload))
227 | print r.status_code
228 | except Exception, e:
229 | logger.exception(e)
230 |
231 | time.sleep(5)
232 |
233 |
234 |
235 | start()
236 | exit()
237 |
238 | """
239 |
240 | _task_wait_list = []
241 | _task_doing_list = []
242 |
243 | def dispatch():
244 | while 1:
245 | time.sleep(1)
246 | lock _task_wait_list
247 | if len(_task_wait_list) != 0:
248 | pop
249 | get thread to do task
250 | unlock _task_wait_list
251 |
252 | def get_task_status():
253 | pass
254 |
255 |
256 | """
257 | def task_is_expired(task_item):
258 | pass
259 | def task_handling(task_item):
260 |
261 | pass
262 | def task_done(task_item):
263 | pass
264 |
265 | #pool = threadpool.ThreadPool(10)
266 | #start()
267 |
268 |
269 |
270 |
271 |
272 |
273 |
--------------------------------------------------------------------------------
/agent/constants.py:
--------------------------------------------------------------------------------
1 | #img_path = "/home/louzhengwei/test/sdb2/img/"
2 |
3 |
4 | img_root_path = "/img"
5 | img_os_path = "/img/os"
6 | img_data_path = "/img/data"
7 | img_template_path = "/img/template"
8 | iso_path = "/img/iso"
9 |
10 | vm_status_running = 1
11 | vm_status_shutoff = 5
12 |
13 | ERROR_MSG_EXPIRED = "task is expired"
14 | ERROR_MSG_TYPE_INVALID = "task type is invalid"
15 | ERROR_MSG_FORMAT_INVALID = "task format is invalid"
16 | ERROR_MSG_HANDLE = "task handle is invalid"
17 |
18 | url_status = 'http://192.168.1.107:8000/api/kvm/'
19 | url_task = 'http://192.168.1.107:8000/api/task/'
20 |
--------------------------------------------------------------------------------
/agent/disk.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/agent/host.py:
--------------------------------------------------------------------------------
1 | import xml.etree.ElementTree as ET
2 | from log import logger
3 | import os, sys
4 | import libvirt
5 | import constants
6 |
7 | import subprocess
8 | import commands
9 | import time
10 | import urllib
11 | import re
12 | import urllib2
13 |
14 |
15 | class vmmhost:
16 | def __init__(self, sn, conn):
17 | self.conn = conn
18 | self.sn = sn
19 |
20 | def get_vmlist(self):
21 | dom_names = []
22 | for dom in self.conn.listAllDomains():
23 | dom_names.append(dom.name())
24 | return dom_names
25 |
26 | def get_sw_info(self):
27 | ret = {}
28 | hv_ver = self.conn.getVersion()
29 | major = hv_ver / 1000000
30 | minor = hv_ver % 1000000 / 1000
31 | release = hv_ver % 1000
32 | hv_ver = str(major)+'.'+str(minor)+'.'+str(release)
33 |
34 | lib_ver = self.conn.getLibVersion()
35 | major = lib_ver / 1000000
36 | minor = lib_ver % 1000000 / 1000
37 | release = lib_ver % 1000
38 | lib_ver = str(major)+'.'+str(minor)+'.'+str(release)
39 |
40 | abspath = os.path.dirname(os.path.abspath(__file__))
41 | cli_ver = open(abspath + "/VERSION").readline().rstrip('\r\n')
42 |
43 | cmd = "uname -r"
44 | os_ver = commands.getoutput(cmd)
45 |
46 | ret['version'] = cli_ver
47 | ret['libvirt_version'] = lib_ver
48 | ret['hv_version'] = hv_ver
49 | ret['os_version'] = os_ver
50 | return ret
51 |
52 | def get_out_ip(self):
53 | response = urllib2.urlopen('http://www.ip.cn')
54 | html = response.read()
55 | ip=re.search(r'code.(.*?)..code',html)
56 | return ip.group(1)
57 |
58 | def get_hw_info(self):
59 | ret = {}
60 | cmd = "lscpu | grep '^Arch' | awk '{print $2}'"
61 | result = commands.getoutput(cmd)
62 | ret['architecture'] = result
63 |
64 | cmd = "lscpu | grep '^CPU(s)' | awk '{print $2}'"
65 | result = commands.getoutput(cmd)
66 | ret['cpus'] = int(result)
67 |
68 | cmd = "lscpu | grep '^Model name' | awk -F: '{print $2}'"
69 | result = commands.getoutput(cmd)
70 | ret['cpu_name'] = result.strip()
71 | disk_size_cmd = "lsblk -b --output=NAME,SIZE | grep '^.d' | awk '{printf(\"%s\\n%s\\n\", $1,$2)}'"
72 | cmd_result = commands.getoutput(disk_size_cmd)
73 | disk_size = 0
74 | disk_num = 0
75 | disk_info = []
76 | i = 0
77 | #for i < len(cmd_result):
78 | cmd_result_list = cmd_result.splitlines()
79 | while i < len(cmd_result_list):
80 | #for item in cmd_result.splitlines():
81 | disk_item = {}
82 | disk_item['name'] = cmd_result_list[i]
83 | i += 1
84 | disk_item['size'] = cmd_result_list[i]
85 | i += 1
86 | disk_info.append(disk_item)
87 | disk_size += int(disk_item['size'])
88 | disk_num += 1
89 | ret['disk'] = disk_info
90 | ret['disk_size'] = disk_size
91 | ret['data_disk_num'] = disk_num
92 |
93 | nodeinfo = self.conn.getInfo()
94 | '''
95 | print('Model: '+str(nodeinfo[0]))
96 | print('Memory size: '+str(nodeinfo[1])+'MB')
97 | print('Number of CPUs: '+str(nodeinfo[2]))
98 | print('MHz of CPUs: '+str(nodeinfo[3]))
99 | print('Number of NUMA nodes: '+str(nodeinfo[4]))
100 | print('Number of CPU sockets: '+str(nodeinfo[5]))
101 | print('Number of CPU cores per socket: '+str(nodeinfo[6]))
102 | print('Number of CPU threads per core: '+str(nodeinfo[7]))
103 | '''
104 | ret['total_mem'] = int(nodeinfo[1])*1024*1024
105 |
106 | return ret
107 |
108 | def get_memory_usage(self):
109 | """
110 | Function return memory usage on node.
111 | """
112 | get_all_mem = self.conn.getInfo()[1] * 1048576
113 | get_freemem = self.conn.getMemoryStats(-1, 0)
114 | print get_freemem
115 | if type(get_freemem) == dict:
116 | free = (get_freemem.values()[0] +
117 | get_freemem.values()[2] +
118 | get_freemem.values()[3]) * 1024
119 | percent = ("%2.f" % (100 - ((free * 100 * 1.0) / get_all_mem)))
120 | usage = (get_all_mem - free)
121 | mem_usage = {
122 | 'mem_all': get_all_mem,
123 | 'mem_free': free,
124 | 'mem_usage': percent
125 | }
126 | else:
127 | mem_usage = None
128 |
129 | return mem_usage
130 |
131 | def get_cpu_usage(self):
132 | """
133 | Function return cpu usage on node.
134 | """
135 | prev_idle = 0
136 | prev_total = 0
137 | cpu = self.conn.getCPUStats(-1, 0)
138 | if type(cpu) == dict:
139 | for num in range(2):
140 | idle = self.conn.getCPUStats(-1, 0).values()[1]
141 | total = sum(self.conn.getCPUStats(-1, 0).values())
142 | diff_idle = idle - prev_idle
143 | diff_total = total - prev_total
144 | diff_usage = ("%.2f" % ((1000 * (diff_total - diff_idle) * 1.0 / diff_total + 5) / 10))
145 | prev_total = total
146 | prev_idle = idle
147 | if num == 0:
148 | time.sleep(1)
149 | else:
150 | if diff_usage < 0:
151 | diff_usage = 0
152 | else:
153 | return None
154 | return {'cpu_usage': diff_usage}
155 |
156 | def get_rx_tx(self, itface):
157 | try:
158 | cmd_rx = "cat /sys/class/net/%s/statistics/rx_bytes" % itface
159 | cmd_tx = "cat /sys/class/net/%s/statistics/tx_bytes" % itface
160 | data_rx_prev = commands.getoutput(cmd_rx)
161 | data_tx_prev = commands.getoutput(cmd_tx)
162 |
163 | time.sleep(1)
164 | data_rx_now = commands.getoutput(cmd_rx)
165 | data_tx_now = commands.getoutput(cmd_tx)
166 |
167 | rx = (float(data_rx_now) - float(data_rx_prev))/1024
168 | rx = ("%.2f" % rx)
169 | tx = (float(data_tx_now) - float(data_tx_prev))/1024
170 | tx = ("%.2f" % tx)
171 |
172 | except Exception, e:
173 | logger.exception(e)
174 | return None
175 |
176 | return {"in" : rx, "out" : tx}
177 |
178 |
179 | def get_net_usage(self, itfaces = ["ovirtmgmt"]):
180 | ret = []
181 |
182 | for itface in itfaces:
183 | item = {}
184 | item['name'] = itface
185 | item['type'] = 'service'
186 | rx_tx = self.get_rx_tx(itface)
187 | if rx_tx is not None:
188 | item['in'] = rx_tx['in']
189 | item['out'] = rx_tx['out']
190 |
191 | ret.append(item)
192 | return ret
193 |
194 | def get_disk_usage(self):
195 | """
196 | Function return cpu usage on node.
197 | """
198 | ret_list = []
199 | cmd = "df -l | grep -v ^Filesystem "
200 | result = commands.getoutput(cmd)
201 | for item in result.splitlines():
202 | ret_list.append({})
203 |
204 | col = ("source", "size", "avail", "pcent", "target")
205 | for item_col in col:
206 | i = 0
207 | cmd = "df -l --output=%s | awk 'NR>1 {print $0}'" % item_col
208 | result = commands.getoutput(cmd)
209 | for item in result.splitlines():
210 | ret_list[i][item_col] = item.strip()
211 | i += 1
212 |
213 | logger.debug(ret_list)
214 | #delete tmpfs: delete the one that does not begin with '/'
215 | for index in range(len(ret_list)-1, -1, -1):
216 | if re.match('/', ret_list[index]["source"]) is None:
217 | del(ret_list[index])
218 | else:
219 | #add column: util
220 | cmd = "iostat -x %s | grep -A1 util | tail -1 | awk '{print $NF}' " % ret_list[index]["source"]
221 | result = commands.getoutput(cmd)
222 | ret_list[index]['util'] = float(result)*100
223 | #delete character '%'
224 | ret_list[index]['pcent'] = ("%.2f" % float(ret_list[index]['pcent'][:-1]))
225 |
226 | return ret_list
227 |
228 | def get_hostname(self):
229 | return self.conn.getHostname()
230 |
231 | def get_resource_info(self):
232 | pass
233 |
234 | @staticmethod
235 | def get_file_list(path):
236 | ret_list = []
237 | files = os.listdir(path)
238 | for fi in files:
239 | if os.path.isfile(os.path.join(path, fi)):
240 | ret_list.append(fi)
241 |
242 | return ret_list
243 |
244 | def download_res(self, url, checksum, save_to_path):
245 | i = 1
246 | percent = 0
247 | def report(count, blockSize, totalSize):
248 | percent = int(count*blockSize*100/totalSize)
249 | sys.stdout.write("\r %d %d %d%%" % (i, count, percent) + ' complete')
250 | sys.stdout.flush()
251 | filename = commands.getoutput('basename %s' % url)
252 | print '1111'
253 | urllib.urlretrieve(url, save_to_path + '/' + filename, reporthook=report)
254 | print '22222'
255 | pass
256 |
257 | @staticmethod
258 | def report(count, blockSize, totalSize):
259 | percent = int(count*blockSize*100/totalSize)
260 | sys.stdout.write("\r %d %d%%" % (count, percent) + ' complete')
261 | sys.stdout.flush()
262 |
--------------------------------------------------------------------------------
/agent/log.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | #logging.config.fileConfig("logging.conf")
4 | logger = logging.getLogger()
5 |
6 | fh = logging.FileHandler('/tmp/test.log')
7 | ch = logging.StreamHandler()
8 |
9 | formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(threadName)s - %(filename)s:%(lineno)d:%(funcName)s - %(message)s')
10 | fh.setFormatter(formatter)
11 | ch.setFormatter(formatter)
12 |
13 | logger.addHandler(fh)
14 | logger.addHandler(ch)
15 |
16 | logger.setLevel(logging.DEBUG)
17 |
18 |
19 |
--------------------------------------------------------------------------------
/agent/test/1.xml:
--------------------------------------------------------------------------------
1 |
2 | vm_name1
3 | 92b4e1bc-acbf-4873-9a1f-be17f7425aa9
4 | 2097152
5 | 2097152
6 | 16
7 |
8 | 1020
9 |
10 |
11 |
12 | oVirt
13 | oVirt Node
14 | 7-1.1503.el7.centos.2.8
15 |
16 |
17 |
18 | hvm
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | Nehalem
27 |
28 |
29 | |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | destroy
38 | restart
39 | destroy
40 |
41 | /usr/libexec/qemu-kvm
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/agent/test/111.qcow2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/agent/test/111.qcow2
--------------------------------------------------------------------------------
/agent/test/2.xml:
--------------------------------------------------------------------------------
1 |
2 | vm_name1
3 | 2097152
4 | 2097152
5 | 16
6 |
7 | 1020
8 |
9 |
10 |
11 | oVirt
12 | oVirt Node
13 | 7-1.1503.el7.centos.2.8
14 |
15 |
16 |
17 | hvm
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | Nehalem
26 |
27 |
28 | |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | destroy
37 | restart
38 | destroy
39 |
40 | /usr/libexec/qemu-kvm
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
90 |
91 |
92 |
93 |
94 |
95 |
--------------------------------------------------------------------------------
/agent/test/build_host_hw.py:
--------------------------------------------------------------------------------
1 | import os,sys
2 | import libvirt
3 | import json
4 |
5 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
6 | sys.path.insert(0,parentdir)
7 |
8 | from client import build_host_hw
9 |
10 | ret = build_host_hw("sn1", "qemu:///system")
11 | print json.dumps(ret)
12 |
13 | #print ret
14 |
--------------------------------------------------------------------------------
/agent/test/build_host_status.py:
--------------------------------------------------------------------------------
1 | import os,sys
2 | import libvirt
3 | import json
4 |
5 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
6 | sys.path.insert(0,parentdir)
7 |
8 | from client import build_host_status
9 |
10 | ret = build_host_status("sn1", "qemu:///system")
11 | print json.dumps(ret)
12 |
13 | #print ret
14 |
--------------------------------------------------------------------------------
/agent/test/build_vm_conf.py:
--------------------------------------------------------------------------------
1 | import os,sys
2 | import libvirt
3 | import json
4 |
5 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
6 | sys.path.insert(0,parentdir)
7 |
8 | from client import build_vm_conf
9 |
10 | ret = build_vm_conf("sn1", "qemu:///system")
11 | print json.dumps(ret)
12 |
13 | #print ret
14 |
--------------------------------------------------------------------------------
/agent/test/build_vm_status.py:
--------------------------------------------------------------------------------
1 | import os,sys
2 | import libvirt
3 | import json
4 |
5 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
6 | sys.path.insert(0,parentdir)
7 |
8 | from client import build_vm_status
9 |
10 | ret = build_vm_status("sn1", "qemu:///system")
11 | print json.dumps(ret)
12 |
13 | #print ret
14 |
--------------------------------------------------------------------------------
/agent/test/cdrom_xml.py:
--------------------------------------------------------------------------------
1 | import os,sys
2 |
3 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
4 | sys.path.insert(0,parentdir)
5 |
6 | from xml_api import cdrom_xml
7 |
8 | cdrom_xml("block", "_path", 1)
9 | cdrom_xml("file", "_path", 2)
10 | cdrom_xml("block", "_path", 100)
11 | #disk_xml('block', 'aaa/a', 1)
12 | #disk_xml('file', 'aaa/a', 2)
13 |
--------------------------------------------------------------------------------
/agent/test/cds.xml:
--------------------------------------------------------------------------------
1 |
2 | cds
3 | 639f3a83-d54a-4ec1-a51d-1dbde1dc1895
4 | 2096128
5 | 2096128
6 | 12
7 |
8 | /machine
9 |
10 |
11 | hvm
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | destroy
21 | restart
22 | restart
23 |
24 | /usr/libexec/qemu-kvm
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | system_u:object_r:svirt_image_t:s0:c242,c889
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/agent/test/cds222.xml:
--------------------------------------------------------------------------------
1 |
2 | cds
3 | 639f3a83-d54a-4ec1-a51d-1dbde1dc1895
4 | 2096000
5 | 2096000
6 | 12
7 |
8 | hvm
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | destroy
18 | restart
19 | restart
20 |
21 | /usr/libexec/qemu-kvm
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/agent/test/disk_xml.py:
--------------------------------------------------------------------------------
1 | import os,sys
2 |
3 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
4 | sys.path.insert(0,parentdir)
5 |
6 | from xml_api import hd_xml
7 |
8 | hd_xml('block', 'aaa/a', 1)
9 | hd_xml('file', 'aaa/aa', 2)
10 |
11 |
--------------------------------------------------------------------------------
/agent/test/file1.py:
--------------------------------------------------------------------------------
1 | import os
2 | from path2.file3 import syspath2
3 | from path2.file3 import syspath3
4 |
5 | syspath1 = os.getcwd()
6 |
7 | print syspath1
8 | print syspath2
9 | print syspath3
10 |
--------------------------------------------------------------------------------
/agent/test/hd_xml.py:
--------------------------------------------------------------------------------
1 | import os,sys
2 |
3 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
4 | sys.path.insert(0,parentdir)
5 |
6 | from xml_api import hd_xml
7 |
8 | hd = hd_xml("block", "_path", 1)
9 | hd = hd_xml("file", "_path", 2)
10 | hd = hd_xml("block", "_path", 100)
11 | #disk_xml('block', 'aaa/a', 1)
12 | #disk_xml('file', 'aaa/a', 2)
13 |
--------------------------------------------------------------------------------
/agent/test/host_getMaxVcpus.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function
2 | import sys
3 | import libvirt
4 | conn = libvirt.open('qemu:///system')
5 | if conn == None:
6 | print('Failed to open connection to qemu:///system', file=sys.stderr)
7 | exit(1)
8 | vcpus = conn.getMaxVcpus(None)
9 | print('Maximum support virtual CPUs: '+str(vcpus))
10 | conn.close()
11 |
--------------------------------------------------------------------------------
/agent/test/host_get_file_list.py:
--------------------------------------------------------------------------------
1 | import os,sys
2 | import libvirt
3 |
4 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
5 | sys.path.insert(0,parentdir)
6 |
7 | from host import vmmhost
8 | from vm import vm
9 |
10 | cvm = vm()
11 | conn = libvirt.open("qemu:///system")
12 | chost = vmmhost('123123', conn)
13 | ret = vmmhost.get_file_list("/root/")
14 | print ret
15 |
16 | #print ret
17 |
--------------------------------------------------------------------------------
/agent/test/host_get_hw_info.py:
--------------------------------------------------------------------------------
1 | import os,sys
2 | import libvirt
3 |
4 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
5 | sys.path.insert(0,parentdir)
6 |
7 | from host import vmmhost
8 | from vm import vm
9 |
10 | cvm = vm()
11 | conn = libvirt.open("qemu:///system")
12 | chost = vmmhost('123123', conn)
13 | ret = chost.get_hw_info()
14 | print ret
15 |
16 | #print ret
17 |
--------------------------------------------------------------------------------
/agent/test/host_get_iso.py:
--------------------------------------------------------------------------------
1 | import os,sys
2 | import libvirt
3 |
4 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
5 | sys.path.insert(0,parentdir)
6 |
7 | from host import vmmhost
8 | from vm import vm
9 |
10 | cvm = vm()
11 | conn = libvirt.open("qemu:///system")
12 | chost = vmmhost('123123', conn)
13 | ret = chost.download_res("http://download.microsoft.com/download/B/8/9/B898E46E-CBAE-4045-A8E2-2D33DD36F3C4/vs2015.pro_chs.iso", "123","/home/louzhengwei/test/sdb2/iso/" )
14 | print ret
15 |
16 | #print ret
17 |
--------------------------------------------------------------------------------
/agent/test/host_get_resource.py:
--------------------------------------------------------------------------------
1 | import os,sys
2 | import libvirt
3 |
4 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
5 | sys.path.insert(0,parentdir)
6 |
7 | from host import vmmhost
8 | from vm import vm
9 |
10 | cvm = vm()
11 | conn = libvirt.open("qemu:///system")
12 | chost = vmmhost('123123', conn)
13 | ret = chost.get_memory_usage()
14 | print ret
15 | ret = chost.get_cpu_usage()
16 | print ret
17 | ret = chost.get_disk_usage()
18 |
--------------------------------------------------------------------------------
/agent/test/host_get_sw_info.py:
--------------------------------------------------------------------------------
1 | import os,sys
2 | import libvirt
3 |
4 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
5 | sys.path.insert(0,parentdir)
6 |
7 | from host import vmmhost
8 | from vm import vm
9 |
10 | cvm = vm()
11 | conn = libvirt.open("qemu:///system")
12 | chost = vmmhost('123123', conn)
13 | #print chost.get_cpu_usage()
14 | print chost.get_net_usage()
15 | #print chost.get_memory_usage()
16 | #print chost.get_sw_info()
17 |
--------------------------------------------------------------------------------
/agent/test/host_nodeinfo.py:
--------------------------------------------------------------------------------
1 | # Example-12.py
2 | from __future__ import print_function
3 | import sys
4 | import libvirt
5 | conn = libvirt.open('qemu:///system')
6 | if conn == None:
7 | print('Failed to open connection to qemu:///system', file=sys.stderr)
8 | exit(1)
9 | nodeinfo = conn.getInfo()
10 | print('Model: '+str(nodeinfo[0]))
11 | print('Memory size: '+str(nodeinfo[1])+'MB')
12 | print('Number of CPUs: '+str(nodeinfo[2]))
13 | print('MHz of CPUs: '+str(nodeinfo[3]))
14 | print('Number of NUMA nodes: '+str(nodeinfo[4]))
15 | print('Number of CPU sockets: '+str(nodeinfo[5]))
16 | print('Number of CPU cores per socket: '+str(nodeinfo[6]))
17 | print('Number of CPU threads per core: '+str(nodeinfo[7]))
18 |
19 | conn.close()
20 | exit(0)
21 |
--------------------------------------------------------------------------------
/agent/test/path.py:
--------------------------------------------------------------------------------
1 | import sys,os
2 | def cur_file_dir():
3 | path = sys.path[0]
4 | if os.path.isdir(path):
5 | return path
6 | elif os.path.isfile(path):
7 | return os.path.dirname(path)
8 | print cur_file_dir()
9 |
--------------------------------------------------------------------------------
/agent/test/prepare_img.py:
--------------------------------------------------------------------------------
1 | task_dict ={ "create_time": "2010-01-01 00:00:00", "id":1, "age": 3600, "type": 1, "vm_name": "xingyu", "formula": "", "topology" : { "cpu" : 1, "disk" : 1}, "cpu_num":2, "memory":512000000, "disk_os":30, "disk_data":100, "install_method": 0, "vm_file": "/home/iso/centos6.7-for-xingyu.iso", "father_id": 1}
2 |
3 | import os,sys
4 |
5 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
6 | sys.path.insert(0,parentdir)
7 | import os,sys
8 |
9 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
10 | sys.path.insert(0,parentdir)
11 |
12 | from vm import vm
13 | import task
14 |
15 | a = vm("cds")
16 | ctask = task.task(task_dict)
17 | a.prepare_img(ctask)
18 |
19 |
--------------------------------------------------------------------------------
/agent/test/snapshot_xml.py:
--------------------------------------------------------------------------------
1 | import os,sys
2 |
3 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
4 | sys.path.insert(0,parentdir)
5 |
6 | from xml_api import construct_snapshot_xml
7 | import xml.etree.ElementTree as ET
8 |
9 | root = construct_snapshot_xml("name1", ["22", "32"])
10 | print ET.tostring(root)
11 |
12 |
--------------------------------------------------------------------------------
/agent/test/task_action.py:
--------------------------------------------------------------------------------
1 | task_dict ={ "create_time": "2010-01-01 00:00:00", "id":1, "age": 3600,
2 | "type": 1, "vm_name": "xingyu", "formula": "", "topology" : { "cpu" : 1, "disk" : 1},
3 | "cpu_num":2,
4 | "memory":512000000,
5 | "disk_os":30000000,
6 | "disk_data":1000000000,
7 | "install_method": 0,
8 | "vm_file": "/home/iso/centos6.7-for-xingyu.iso",
9 | "father_id": 1,
10 | "uri":"http://download.microsoft.com/download/B/8/9/B898E46E-CBAE-4045-A8E2-2D33DD36F3C4/vs2015.pro_chs.iso",
11 | "save_path":"/home/",
12 | "md5": "111",
13 | "action": "stop",
14 |
15 |
16 | }
17 |
18 | task_dict2 ={ "create_time": "2010-01-01 00:00:00", "id":1, "age": 3600,
19 | "type": 1, "vm_name": "xingyu", "formula": "", "topology" : { "cpu" : 1, "disk" : 1},
20 | "cpu_num":2,
21 | "memory":512000000,
22 | "disk_os":30,
23 | "disk_data":100,
24 | "install_method": 1,
25 | "vm_file": "/home/iso/centos6.7-for-xingyu.iso",
26 | "father_id": 1,
27 | "uri":"http://download.microsoft.com/download/B/8/9/B898E46E-CBAE-4045-A8E2-2D33DD36F3C4/vs2015.pro_chs.iso",
28 | "save_path":"/home/",
29 | "md5": "111",
30 |
31 |
32 | }
33 | import os,sys
34 |
35 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
36 | sys.path.insert(0,parentdir)
37 |
38 | from vm import vm
39 | from host import vmmhost
40 | import task
41 |
42 | a = vm("cds")
43 | tm = task.task_manager()
44 | ctask = task.task(task_dict)
45 |
46 | tm.task_action(ctask)
47 |
48 |
--------------------------------------------------------------------------------
/agent/test/task_create_snapshot.py:
--------------------------------------------------------------------------------
1 | task_dict ={ "create_time": "2010-01-01 00:00:00", "id":1, "age": 3600,
2 | "type": 1, "vm_name": "xingyu", "formula": "", "topology" : { "cpu" : 1, "disk" : 1},
3 | "cpu_num":2,
4 | "memory":512000000,
5 | "disk_os":30000000,
6 | "disk_data":1000000000,
7 | "install_method": 0,
8 | "vm_file": "/home/iso/centos6.7-for-xingyu.iso",
9 | "father_id": 1,
10 | "uri":"http://download.microsoft.com/download/B/8/9/B898E46E-CBAE-4045-A8E2-2D33DD36F3C4/vs2015.pro_chs.iso",
11 | "save_path":"/home/",
12 | "md5": "111",
13 |
14 | "snapshot_name": "snap3",
15 |
16 |
17 | }
18 |
19 | task_dict2 ={ "create_time": "2010-01-01 00:00:00", "id":1, "age": 3600,
20 | "type": 1, "vm_name": "xingyu", "formula": "", "topology" : { "cpu" : 1, "disk" : 1},
21 | "cpu_num":2,
22 | "memory":512000000,
23 | "disk_os":30,
24 | "disk_data":100,
25 | "install_method": 1,
26 | "vm_file": "/home/iso/centos6.7-for-xingyu.iso",
27 | "father_id": 1,
28 | "uri":"http://download.microsoft.com/download/B/8/9/B898E46E-CBAE-4045-A8E2-2D33DD36F3C4/vs2015.pro_chs.iso",
29 | "save_path":"/home/",
30 | "md5": "111",
31 |
32 |
33 | }
34 | import os,sys
35 |
36 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
37 | sys.path.insert(0,parentdir)
38 |
39 | from vm import vm
40 | from host import vmmhost
41 | import task
42 |
43 | a = vm("cds")
44 | tm = task.task_manager()
45 | ctask = task.task(task_dict)
46 |
47 | tm.task_create_snapshot(ctask)
48 |
49 |
--------------------------------------------------------------------------------
/agent/test/task_define.py:
--------------------------------------------------------------------------------
1 | task_dict ={ "create_time": "2010-01-01 00:00:00", "id":1, "age": 3600,
2 | "type": 1, "vm_name": "xingyu", "formula": "", "topology" : { "cpu" : 1, "disk" : 1},
3 | "cpu_num":2,
4 | "memory":512000000,
5 | "disk_os":30000000,
6 | "disk_data":1000000000,
7 | "install_method": 0,
8 | "vm_file": "/home/iso/centos6.7-for-xingyu.iso",
9 | "father_id": 1,
10 | "uri":"http://download.microsoft.com/download/B/8/9/B898E46E-CBAE-4045-A8E2-2D33DD36F3C4/vs2015.pro_chs.iso",
11 | "save_path":"/home/",
12 | "md5": "111",
13 |
14 |
15 | }
16 |
17 | task_dict2 ={ "create_time": "2010-01-01 00:00:00", "id":1, "age": 3600,
18 | "type": 1, "vm_name": "xingyu", "formula": "", "topology" : { "cpu" : 1, "disk" : 1},
19 | "cpu_num":2,
20 | "memory":512000000,
21 | "disk_os":30,
22 | "disk_data":100,
23 | "install_method": 1,
24 | "vm_file": "/home/iso/centos6.7-for-xingyu.iso",
25 | "father_id": 1,
26 | "uri":"http://download.microsoft.com/download/B/8/9/B898E46E-CBAE-4045-A8E2-2D33DD36F3C4/vs2015.pro_chs.iso",
27 | "save_path":"/home/",
28 | "md5": "111",
29 |
30 |
31 | }
32 | import os,sys
33 |
34 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
35 | sys.path.insert(0,parentdir)
36 |
37 | from vm import vm
38 | from host import vmmhost
39 | import task
40 |
41 | a = vm("cds")
42 | tm = task.task_manager()
43 | ctask = task.task(task_dict)
44 |
45 | tm.task_define(ctask)
46 |
47 |
--------------------------------------------------------------------------------
/agent/test/task_delete.py:
--------------------------------------------------------------------------------
1 | task_dict ={ "create_time": "2010-01-01 00:00:00", "id":1, "age": 3600,
2 | "type": 1, "vm_name": "xingyu", "formula": "", "topology" : { "cpu" : 1, "disk" : 1},
3 | "cpu_num":2,
4 | "memory":512000000,
5 | "disk_os":30000000,
6 | "disk_data":1000000000,
7 | "install_method": 0,
8 | "vm_file": "/home/iso/centos6.7-for-xingyu.iso",
9 | "father_id": 1,
10 | "uri":"http://download.microsoft.com/download/B/8/9/B898E46E-CBAE-4045-A8E2-2D33DD36F3C4/vs2015.pro_chs.iso",
11 | "save_path":"/home/",
12 | "delete_disk":1,
13 | "md5": "111",
14 |
15 |
16 | }
17 |
18 | task_dict2 ={ "create_time": "2010-01-01 00:00:00", "id":1, "age": 3600,
19 | "type": 1, "vm_name": "xingyu", "formula": "", "topology" : { "cpu" : 1, "disk" : 1},
20 | "cpu_num":2,
21 | "memory":512000000,
22 | "disk_os":30,
23 | "disk_data":100,
24 | "install_method": 1,
25 | "vm_file": "/home/iso/centos6.7-for-xingyu.iso",
26 | "father_id": 1,
27 | "uri":"http://download.microsoft.com/download/B/8/9/B898E46E-CBAE-4045-A8E2-2D33DD36F3C4/vs2015.pro_chs.iso",
28 | "save_path":"/home/",
29 | "md5": "111",
30 |
31 |
32 | }
33 | import os,sys
34 |
35 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
36 | sys.path.insert(0,parentdir)
37 |
38 | from vm import vm
39 | from host import vmmhost
40 | import task
41 |
42 | a = vm("cds")
43 | tm = task.task_manager()
44 | ctask = task.task(task_dict)
45 |
46 | tm.task_delete(ctask)
47 |
--------------------------------------------------------------------------------
/agent/test/task_delete_snapshot.py:
--------------------------------------------------------------------------------
1 | task_dict ={ "create_time": "2010-01-01 00:00:00", "id":1, "age": 3600,
2 | "type": 1, "vm_name": "xingyu", "formula": "", "topology" : { "cpu" : 1, "disk" : 1},
3 | "cpu_num":2,
4 | "memory":512000000,
5 | "disk_os":30000000,
6 | "disk_data":1000000000,
7 | "install_method": 0,
8 | "vm_file": "/home/iso/centos6.7-for-xingyu.iso",
9 | "father_id": 1,
10 | "uri":"http://download.microsoft.com/download/B/8/9/B898E46E-CBAE-4045-A8E2-2D33DD36F3C4/vs2015.pro_chs.iso",
11 | "save_path":"/home/",
12 | "md5": "111",
13 |
14 | "snapshot_name": "snap2",
15 |
16 |
17 | }
18 |
19 | task_dict2 ={ "create_time": "2010-01-01 00:00:00", "id":1, "age": 3600,
20 | "type": 1, "vm_name": "xingyu", "formula": "", "topology" : { "cpu" : 1, "disk" : 1},
21 | "cpu_num":2,
22 | "memory":512000000,
23 | "disk_os":30,
24 | "disk_data":100,
25 | "install_method": 1,
26 | "vm_file": "/home/iso/centos6.7-for-xingyu.iso",
27 | "father_id": 1,
28 | "uri":"http://download.microsoft.com/download/B/8/9/B898E46E-CBAE-4045-A8E2-2D33DD36F3C4/vs2015.pro_chs.iso",
29 | "save_path":"/home/",
30 | "md5": "111",
31 |
32 |
33 | }
34 | import os,sys
35 |
36 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
37 | sys.path.insert(0,parentdir)
38 |
39 | from vm import vm
40 | from host import vmmhost
41 | import task
42 |
43 | a = vm("cds")
44 | tm = task.task_manager()
45 | ctask = task.task(task_dict)
46 |
47 | tm.task_delete_snapshot(ctask)
48 |
49 |
--------------------------------------------------------------------------------
/agent/test/task_download.py:
--------------------------------------------------------------------------------
1 | task_dict ={ "create_time": "2010-01-01 00:00:00", "id":1, "age": 3600,
2 | "type": 40, "vm_name": "xingyu", "formula": "", "topology" : { "cpu" : 1, "disk" : 1},
3 | "cpu_num":2,
4 | "memory":512000000,
5 | "disk_os":30,
6 | "disk_data":100,
7 | "install_method": 0,
8 | "vm_file": "/home/iso/centos6.7-for-xingyu.iso",
9 | "father_id": 1,
10 | "uri":"http://download.microsoft.com/download/B/8/9/B898E46E-CBAE-4045-A8E2-2D33DD36F3C4/vs2015.pro_chs.iso",
11 | "save_path":"/img/iso/",
12 | "md5": "111",
13 |
14 |
15 | }
16 |
17 | import os,sys
18 |
19 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
20 | sys.path.insert(0,parentdir)
21 | import os,sys
22 |
23 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
24 | sys.path.insert(0,parentdir)
25 |
26 | from vm import vm
27 | from host import vmmhost
28 | import task
29 |
30 | a = vm("cds")
31 | tm = task.task_manager()
32 | ctask = task.task(task_dict)
33 |
34 | tm.task_download(ctask)
35 |
36 |
--------------------------------------------------------------------------------
/agent/test/task_edit.py:
--------------------------------------------------------------------------------
1 | task_dict ={ "create_time": "2010-01-01 00:00:00", "id":1, "age": 3600,
2 | "type": 2, "vm_name": "xingyu", "formula": "", "topology" : { "cpu" : 1, "disk" : 1},
3 | "cpu_num":2,
4 | "memory":512000000,
5 | "disk_os":30000000,
6 | "disk_data":1000000000,
7 | "sysdisk_extend":5000000,
8 | "datadisk_extend":5000000,
9 | "mem":1000,
10 | "cpu":3,
11 | "install_method": 0,
12 | "vm_file": "/home/iso/centos6.7-for-xingyu.iso",
13 | "father_id": 1,
14 | "uri":"http://download.microsoft.com/download/B/8/9/B898E46E-CBAE-4045-A8E2-2D33DD36F3C4/vs2015.pro_chs.iso",
15 | "save_path":"/home/",
16 | "md5": "111",
17 |
18 |
19 | }
20 |
21 | task_dict2 ={ "create_time": "2010-01-01 00:00:00", "id":1, "age": 3600,
22 | "type": 1, "vm_name": "xingyu", "formula": "", "topology" : { "cpu" : 1, "disk" : 1},
23 | "cpu_num":2,
24 | "memory":512000000,
25 | "disk_os":30,
26 | "disk_data":100,
27 | "install_method": 1,
28 | "vm_file": "/home/iso/centos6.7-for-xingyu.iso",
29 | "father_id": 1,
30 | "uri":"http://download.microsoft.com/download/B/8/9/B898E46E-CBAE-4045-A8E2-2D33DD36F3C4/vs2015.pro_chs.iso",
31 | "save_path":"/home/",
32 | "md5": "111",
33 |
34 |
35 | }
36 | import os,sys
37 |
38 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
39 | sys.path.insert(0,parentdir)
40 |
41 | from vm import vm
42 | from host import vmmhost
43 | import task
44 |
45 | a = vm("cds")
46 | tm = task.task_manager()
47 | ctask = task.task(task_dict)
48 |
49 | tm.task_modify(ctask)
50 |
51 |
--------------------------------------------------------------------------------
/agent/test/task_report.py:
--------------------------------------------------------------------------------
1 | task_lists = [
2 | { "create_time": "2010-01-01 00:00:00", "id":10, "age": 3600,
3 | "type": 40, "vm_name": "xingyu", "formula": "", "topology" : { "cpu" : 1, "disk" : 1},
4 | "cpu_num":2,
5 | "memory":512000000,
6 | "disk_os":30000000,
7 | "disk_data":1000000000,
8 | "install_method": 0,
9 | "vm_file": "/home/iso/centos6.7-for-xingyu.iso",
10 | "father_id": 1,
11 | "uri":"http://download.microsoft.com/download/B/8/9/B898E46E-CBAE-4045-A8E2-2D33DD36F3C4/vs2015.pro_chs.iso",
12 | "save_path":"/home/",
13 | "md5": "111",
14 |
15 |
16 | },
17 |
18 | { "create_time": "2010-01-01 00:00:00", "id":11, "age": 3600,
19 | "type": 1, "vm_name": "xingyu", "formula": "", "topology" : { "cpu" : 1, "disk" : 1},
20 | "cpu_num":2,
21 | "memory":512000000,
22 | "disk_os":30,
23 | "disk_data":100,
24 | "install_method": 1,
25 | "vm_file": "/home/iso/centos6.7-for-xingyu.iso",
26 | "father_id": 1,
27 | "uri":"http://111.1.50.20/files/41110000000A2446/download.microsoft.com/download/5/c/1/5c156922-ca10-49d8-b7e7-9bf092c3b6eb/VS2010ExpressCHS.iso",
28 | "save_path":"/home/",
29 | "md5": "111",
30 |
31 |
32 | },
33 | { "create_time": "2010-01-01 00:00:00", "id":12, "age": 3600,
34 | "type": 40, "vm_name": "xingyu", "formula": "", "topology" : { "cpu" : 1, "disk" : 1},
35 | "cpu_num":2,
36 | "memory":512000000,
37 | "disk_os":30,
38 | "disk_data":100,
39 | "install_method": 1,
40 | "vm_file": "/home/iso/centos6.7-for-xingyu.iso",
41 | "father_id": 1,
42 | "uri":"http://111.1.50.20/files/41110000000A2446/download.microsoft.com/download/5/c/1/5c156922-ca10-49d8-b7e7-9bf092c3b6eb/VS2010ExpressCHS.iso",
43 | "save_path":"/home/",
44 | "md5": "111",
45 |
46 |
47 | }
48 | ]
49 |
50 | import os,sys
51 |
52 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
53 | sys.path.insert(0,parentdir)
54 |
55 | from vm import vm
56 | from host import vmmhost
57 | import task
58 |
59 | a = vm("cds")
60 | tm = task.task_manager()
61 | tm.start()
62 | #ctask = task.task(task_dict)
63 |
64 | #tm.run()
65 |
66 |
--------------------------------------------------------------------------------
/agent/test/task_resume_snapshot.py:
--------------------------------------------------------------------------------
1 | task_dict ={ "create_time": "2010-01-01 00:00:00", "id":1, "age": 3600,
2 | "type": 1, "vm_name": "xingyu", "formula": "", "topology" : { "cpu" : 1, "disk" : 1},
3 | "cpu_num":2,
4 | "memory":512000000,
5 | "disk_os":30000000,
6 | "disk_data":1000000000,
7 | "install_method": 0,
8 | "vm_file": "/home/iso/centos6.7-for-xingyu.iso",
9 | "father_id": 1,
10 | "uri":"http://download.microsoft.com/download/B/8/9/B898E46E-CBAE-4045-A8E2-2D33DD36F3C4/vs2015.pro_chs.iso",
11 | "save_path":"/home/",
12 | "md5": "111",
13 |
14 | "snapshot_name": "snap1",
15 |
16 |
17 | }
18 |
19 | task_dict2 ={ "create_time": "2010-01-01 00:00:00", "id":1, "age": 3600,
20 | "type": 1, "vm_name": "xingyu", "formula": "", "topology" : { "cpu" : 1, "disk" : 1},
21 | "cpu_num":2,
22 | "memory":512000000,
23 | "disk_os":30,
24 | "disk_data":100,
25 | "install_method": 1,
26 | "vm_file": "/home/iso/centos6.7-for-xingyu.iso",
27 | "father_id": 1,
28 | "uri":"http://download.microsoft.com/download/B/8/9/B898E46E-CBAE-4045-A8E2-2D33DD36F3C4/vs2015.pro_chs.iso",
29 | "save_path":"/home/",
30 | "md5": "111",
31 |
32 |
33 | }
34 | import os,sys
35 |
36 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
37 | sys.path.insert(0,parentdir)
38 |
39 | from vm import vm
40 | from host import vmmhost
41 | import task
42 |
43 | a = vm("cds")
44 | tm = task.task_manager()
45 | ctask = task.task(task_dict)
46 |
47 | tm.task_restore_snapshot(ctask)
48 |
49 |
--------------------------------------------------------------------------------
/agent/test/task_set_ip.py:
--------------------------------------------------------------------------------
1 | task_dict ={ "create_time": "2018-01-01 00:00:00", "id":1, "age": 3600,
2 | "type": 8, "vm_name": "cds", "formula": "", "topology" : { "cpu" : 1, "disk" : 1},
3 | "cpu_num":2,
4 | "memory":512000000,
5 | "disk_os":30000000,
6 | "disk_data":1000000000,
7 | "sysdisk_extend":5000000,
8 | "datadisk_extend":5000000,
9 | "mem":1000,
10 | "cpu":3,
11 | "install_method": 0,
12 | "vm_file": "/home/iso/centos6.7-for-xingyu.iso",
13 | "father_id": 1,
14 | "uri":"http://download.microsoft.com/download/B/8/9/B898E46E-CBAE-4045-A8E2-2D33DD36F3C4/vs2015.pro_chs.iso",
15 | "save_path":"/home/",
16 | "md5": "111",
17 | "bootproto":"static",
18 | "ip":"192.168.1.46",
19 | "dns":"8.8.8.8",
20 | "gateway":"192.168.1.1",
21 | "netmask":"255.255.255.0",
22 | "nic_name":"bond0",
23 |
24 |
25 |
26 | }
27 |
28 | task_dict2 ={ "create_time": "2010-01-01 00:00:00", "id":1, "age": 3600,
29 | "type": 1, "vm_name": "xingyu", "formula": "", "topology" : { "cpu" : 1, "disk" : 1},
30 | "cpu_num":2,
31 | "memory":512000000,
32 | "disk_os":30,
33 | "disk_data":100,
34 | "install_method": 1,
35 | "vm_file": "/home/iso/centos6.7-for-xingyu.iso",
36 | "father_id": 1,
37 | "uri":"http://download.microsoft.com/download/B/8/9/B898E46E-CBAE-4045-A8E2-2D33DD36F3C4/vs2015.pro_chs.iso",
38 | "save_path":"/home/",
39 | "md5": "111",
40 |
41 |
42 | }
43 | import os,sys
44 |
45 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
46 | sys.path.insert(0,parentdir)
47 |
48 | from vm import vm
49 | from host import vmmhost
50 | import task
51 |
52 | a = vm("cds")
53 | #a.write_vm_file("/etc/sysconfig/network-scripts/ifcfg-bond0", "aaaaa")
54 | tm = task.task_manager()
55 | ctask = task.task(task_dict)
56 |
57 | tm.task_set_ip(ctask)
58 |
59 |
--------------------------------------------------------------------------------
/agent/test/test.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import libvirt
3 |
4 |
5 | conn = libvirt.open('qemu:///system')
6 | if conn == None:
7 | print("Failed to open connection to qemu:///system', file=sys.stderr")
8 | exit(1)
9 |
10 | host = conn.getHostname()
11 | nodeinfo = conn.getInfo()
12 | print('Hostname:'+host)
13 | print('nodeinfo:'+nodeinfo)
14 |
15 | conn.close()
16 | exit(0)
17 |
--------------------------------------------------------------------------------
/agent/test/threadpool_test.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import threadpool
3 | import time,random
4 |
5 |
6 |
7 | def hello(str):
8 | time.sleep(1)
9 | print "1"
10 | return str
11 |
12 | def print_result(request, result):
13 | print "the result is %s %r" % (request.requestID, result)
14 |
15 | data = [random.randint(1,10) for i in range(20)]
16 | print data
17 |
18 | pool = threadpool.ThreadPool(5)
19 | i = 0
20 | li = []
21 | pool.wait()
22 | for it in data:
23 | i += 1
24 | if i%7 != 0:
25 | li.append(it)
26 | else:
27 | requests = threadpool.makeRequests(hello, li, print_result)
28 | [pool.putRequest(req) for req in requests]
29 | li = []
30 |
31 | print "before wait"
32 | #pool.wait()
33 | print "after wait"
34 | time.sleep(10)
35 |
36 |
--------------------------------------------------------------------------------
/agent/test/vm_define.py:
--------------------------------------------------------------------------------
1 |
2 | import os,sys
3 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
4 | sys.path.insert(0,parentdir)
5 | from vm import vm
6 |
7 |
8 | a = vm()
9 | ret = a.define("qemu:///system", "vm_name1", "")
10 | print ret
11 |
--------------------------------------------------------------------------------
/agent/test/vm_destroy.py:
--------------------------------------------------------------------------------
1 | import os,sys
2 |
3 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
4 | sys.path.insert(0,parentdir)
5 | import os,sys
6 |
7 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
8 | sys.path.insert(0,parentdir)
9 |
10 | from vm import vm
11 |
12 | a = vm()
13 | ret = a.destroy("qemu:///system", sys.argv[1])
14 | print ret
15 |
--------------------------------------------------------------------------------
/agent/test/vm_edit_conf.py:
--------------------------------------------------------------------------------
1 | import os,sys
2 |
3 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
4 | sys.path.insert(0,parentdir)
5 |
6 | from vm import vm
7 | import libvirt
8 |
9 | a = vm("cds")
10 | conn = libvirt.open("qemu:///system")
11 | a.change_cur_cpu_number(conn, 4)
12 | a.change_cur_cpu_number(conn, 1)
13 | a.change_cur_cpu_number(conn, 20)
14 |
15 | a.change_memory(1024000)
16 | a.change_memory(4024000)
17 | print ret
18 |
--------------------------------------------------------------------------------
/agent/test/vm_get_info.py:
--------------------------------------------------------------------------------
1 | import os,sys
2 |
3 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
4 | sys.path.insert(0,parentdir)
5 |
6 | from vm import vm
7 |
8 | a = vm('cds')
9 | ret = a.get_info()
10 |
11 | print ret
12 |
--------------------------------------------------------------------------------
/agent/test/vm_get_os_version.py:
--------------------------------------------------------------------------------
1 | import os,sys
2 |
3 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
4 | sys.path.insert(0,parentdir)
5 |
6 | from vm import vm
7 | import libvirt
8 |
9 | a = vm('cds')
10 | conn = libvirt.open("qemu:///system")
11 |
12 | ret = a.get_os_version()
13 |
14 |
15 | print ret
16 |
--------------------------------------------------------------------------------
/agent/test/vm_get_status.py:
--------------------------------------------------------------------------------
1 | import os,sys
2 |
3 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
4 | sys.path.insert(0,parentdir)
5 |
6 | from vm import vm
7 |
8 | a = vm()
9 | ret = a.get_status("qemu:///system", "cds")
10 | ret = a.get_status("qemu:///system", "louzhengwei")
11 |
12 | print ret
13 |
--------------------------------------------------------------------------------
/agent/test/vm_judge_exist.py:
--------------------------------------------------------------------------------
1 |
2 | import os,sys
3 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
4 | sys.path.insert(0,parentdir)
5 | from vm import vm
6 |
7 | a = vm('aaa')
8 |
9 | print a.xml
10 | if a.xml == "":
11 | print "11"
12 | else:
13 | print "22"
14 |
15 |
--------------------------------------------------------------------------------
/agent/test/vm_read_vm_file.py:
--------------------------------------------------------------------------------
1 |
2 | import os,sys
3 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
4 | sys.path.insert(0,parentdir)
5 | from vm import vm
6 |
7 |
8 | a = vm('cds')
9 | ret = a.read_vm_file("/proc/diskstats")
10 | ret = a.read_vm_file("/proc/net/dev")
11 | print ret
12 | ret = a._get_network_interfaces()
13 | print ret
14 | print '11111111111111'
15 |
--------------------------------------------------------------------------------
/agent/test/vm_shutdown.py:
--------------------------------------------------------------------------------
1 | import os,sys
2 |
3 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
4 | sys.path.insert(0,parentdir)
5 |
6 | from vm import vm
7 |
8 | a = vm()
9 | ret = a.shutdown("qemu:///system", "vm_name1")
10 | ret = a.shutdown("qemu:///system", "vm_name1")
11 | ret = a.shutdown("qemu:///system", "vm_name2")
12 | print ret
13 |
--------------------------------------------------------------------------------
/agent/test/vm_start.py:
--------------------------------------------------------------------------------
1 | import os,sys
2 |
3 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
4 | sys.path.insert(0,parentdir)
5 |
6 | from vm import vm
7 |
8 | a = vm()
9 | ret = a.start("qemu:///system", "vm_name1")
10 | ret = a.start("qemu:///system", "vm_name1")
11 | ret = a.start("qemu:///system", "vm_name2")
12 | print ret
13 |
--------------------------------------------------------------------------------
/agent/test/vm_start_from_cdrom.py:
--------------------------------------------------------------------------------
1 |
2 | import os,sys
3 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
4 | sys.path.insert(0,parentdir)
5 | from vm import vm
6 |
7 |
8 | a = vm()
9 | ret = a.start_from_cdrom("qemu:///system", "vm_name1", "cdrom_name1")
10 | print ret
11 |
--------------------------------------------------------------------------------
/agent/test/vm_undefine.py:
--------------------------------------------------------------------------------
1 | import os,sys
2 |
3 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
4 | sys.path.insert(0,parentdir)
5 |
6 | from vm import vm
7 |
8 | a = vm()
9 | ret = a.undefine("qemu:///system", "vm_name1")
10 | ret = a.undefine("qemu:///system", "vm_name1")
11 | ret = a.undefine("qemu:///system", "vm_name2")
12 | print ret
13 |
--------------------------------------------------------------------------------
/agent/test/vm_write_vm_file.py:
--------------------------------------------------------------------------------
1 |
2 | import os,sys
3 | parentdir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
4 | sys.path.insert(0,parentdir)
5 | from vm import vm
6 |
7 |
8 | a = vm('cds')
9 | ret = a.write_vm_file("/abc.txt", "aaa=11")
10 | print ret
11 | print '11111111111111'
12 |
13 |
--------------------------------------------------------------------------------
/agent/test/xingyu.xml:
--------------------------------------------------------------------------------
1 |
2 | xingyu
3 | e04cea40-a827-456e-a9db-14e0458998b3
4 | 500000
5 | 500000
6 | 2
7 |
8 | hvm
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | destroy
18 | restart
19 | restart
20 |
21 | /usr/libexec/qemu-kvm
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/agent/vpe.conf:
--------------------------------------------------------------------------------
1 | [log]
2 | path=/var/log/vpe.log
3 | level=DEBUG
4 |
--------------------------------------------------------------------------------
/agent/xml_api.py:
--------------------------------------------------------------------------------
1 | import xml.etree.ElementTree as ET
2 | from log import logger
3 | import os,sys
4 |
5 | class disk_xml:
6 | def __init__(self):
7 | self.disk_type = ""
8 | self.disk_device = ""
9 | self.driver_type=""
10 | self.target_dev=""
11 | self.target_bus = ""
12 | self.path = ""
13 |
14 | self.driver_cache = "none"
15 | #self.tree = self.init_tree()
16 | self.tree = None #public
17 |
18 | def init_tree(self):
19 | abspath = os.path.dirname(os.path.abspath(__file__))
20 | tree = ET.parse(abspath + '/disk.xml')
21 | root = tree.getroot()
22 | return root
23 |
24 | def construct_disk_xml(self):
25 | self.tree = ET.Element('disk')
26 | self.tree.attrib['type'] = self.disk_type
27 | self.tree.attrib['device'] = self.disk_device
28 | driver_element = ET.SubElement(self.tree, 'driver')
29 | driver_element.attrib['name'] = 'qemu'
30 | driver_element.attrib['type'] = self.driver_type
31 | driver_element.attrib['cache'] = self.driver_cache
32 |
33 | target_element = ET.SubElement(self.tree, 'target')
34 | target_element.attrib['dev'] = self.target_dev
35 | target_element.attrib['bus'] = self.target_bus
36 |
37 | def insert_readonly(self):
38 | ET.SubElement(self.tree, 'readonly')
39 | def insert_address(self):
40 | address_element = ET.SubElement(self.tree, 'address')
41 | address_element.attrib['controller'] = '0'
42 | address_element.attrib['type'] = 'drive'
43 |
44 |
45 | class hd_xml(disk_xml):
46 | def __init__(self, disk_type, path, num, driver_type = "qcow2"):
47 | disk_xml.__init__(self)
48 |
49 | if int(num) >= 32 or int(num) <= 0 :
50 | logger.error("disk number is invalid")
51 | self.tree = None
52 | return
53 | if not path:
54 | logger.error("disk path is None, invalid")
55 | self.tree = None
56 | return
57 |
58 | self.disk_type = disk_type
59 | self.disk_device = "disk"
60 | self.driver_type = driver_type
61 | self.target_dev = 'vd' + chr(ord('a')+ int(num) - 1)
62 | self.target_bus = "virtio"
63 |
64 | self.construct_disk_xml()
65 | self.insert_source(path)
66 |
67 | logger.debug(ET.tostring(self.tree))
68 |
69 | def insert_source(self, path):
70 | source_element = ET.SubElement(self.tree, 'source')
71 | if self.disk_type == "file":
72 | source_element.attrib['file'] = path
73 | pass
74 | elif self.disk_type == "block":
75 | source_element.attrib['dev'] = path
76 | else:
77 | logger.warn("disk_type is invalid")
78 | return None
79 |
80 | class cdrom_xml(disk_xml):
81 | def __init__(self, disk_type, path, num, driver_type = "raw"):
82 | disk_xml.__init__(self)
83 |
84 | if int(num) >= 32 or int(num) <= 0 :
85 | logger.error("disk number is invalid")
86 | self.tree = None
87 | return
88 | if not path:
89 | logger.error("disk path is None, invalid")
90 | self.tree = None
91 | return
92 |
93 | self.disk_type = disk_type
94 | self.disk_device = "cdrom"
95 | self.driver_type = driver_type
96 | self.target_dev = 'hd' + chr(ord('a')+ int(num) - 1)
97 | self.target_bus = "ide"
98 |
99 | self.construct_disk_xml()
100 | self.insert_source(path)
101 | self.insert_readonly()
102 | self.insert_address()
103 |
104 | logger.debug(ET.tostring(self.tree))
105 |
106 | def insert_source(self, path):
107 | source_element = ET.SubElement(self.tree, 'source')
108 | if self.disk_type == "file":
109 | source_element.attrib['file'] = path
110 | pass
111 | else:
112 | logger.warn("disk_type is invalid")
113 | return None
114 |
115 |
116 | """
117 | def construct_disk_xml(type, path, num):
118 |
119 | if not path:
120 | logger.warn("disk path is None, invalid")
121 | return None
122 | if int(num) >= 32 or int(num) <= 0 :
123 | logger.warn("disk number is invalid")
124 | return None
125 |
126 | abspath = os.path.dirname(os.path.abspath(__file__))
127 | tree = ET.parse(abspath + '/disk.xml')
128 | root = tree.getroot()
129 | new_xml = ET.tostring(root)
130 |
131 | if type == "file":
132 | root.attrib['type'] = 'file'
133 | root.find('source').attrib['file'] = path
134 | pass
135 | elif type == "block":
136 | root.attrib['type'] = 'block'
137 | root.find('source').attrib['dev'] = path
138 | else:
139 | logger.warn("disk type is invalid")
140 | return None
141 |
142 | #"the disk's label"
143 | label = 'vd' + chr(ord('a')+ int(num) - 1)
144 | root.find('target').attrib['dev'] = label
145 |
146 | logger.debug(ET.tostring(root))
147 | return root
148 |
149 | def construct_cdrom_xml(path, num):
150 | if not path:
151 | logger.warn("disk path is None, invalid")
152 | return None
153 | if int(num) >= 32 or int(num) <= 0 :
154 | logger.warn("disk number is invalid")
155 | return None
156 |
157 | abspath = os.path.dirname(os.path.abspath(__file__))
158 | tree = ET.parse(abspath + '/cdrom.xml')
159 | root = tree.getroot()
160 | new_xml = ET.tostring(root)
161 |
162 | if type == "file":
163 | root.attrib['type'] = 'file'
164 | root.find('source').attrib['file'] = path
165 | pass
166 | elif type == "block":
167 | root.attrib['type'] = 'block'
168 | root.find('source').attrib['dev'] = path
169 | else:
170 | logger.warn("disk type is invalid")
171 | return None
172 |
173 | #"the disk's label"
174 | label = 'vd' + chr(ord('a')+ int(num) - 1)
175 | root.find('target').attrib['dev'] = label
176 |
177 | logger.debug(ET.tostring(root))
178 | return root
179 |
180 | """
181 |
182 |
183 | def construct_vm_xml(name, mem, cpu):
184 | abspath = os.path.dirname(os.path.abspath(__file__))
185 | tree = ET.parse(abspath + '/base.xml')
186 | root = tree.getroot()
187 |
188 | root.find('name').text = name
189 |
190 | memKB = int(mem)/1024
191 | root.find('memory').text = str(memKB)
192 | root.find('currentMemory').text = str(memKB)
193 |
194 | root.find('vcpu').text = str(cpu)
195 | agent_path = root.find('devices/channel/source').attrib['path']
196 | abs_agent_name = agent_path + name + '.agent'
197 | root.find('devices/channel/source').attrib['path'] = abs_agent_name
198 |
199 | return root
200 |
201 | def construct_snapshot_xml(name, disk_list):
202 | base_xml = """
203 |
204 |
205 |
206 |
207 |
208 | """
209 | root = ET.fromstring(base_xml)
210 | root.find('name').text = name
211 | for item in disk_list:
212 | disk_xml = "" % item
213 | disk_ele = ET.fromstring(disk_xml)
214 | root.find('disks').append(disk_ele)
215 | return root
216 |
217 | def extract_harddisk_labels(vm_xml):
218 | disk_list = []
219 | root = ET.fromstring(vm_xml)
220 | for item in root.findall('devices/disk'):
221 | if item.get('device') == 'disk':
222 | label = item.find('target').get('dev')
223 | if label is not None:
224 | disk_list.append(label)
225 | return disk_list
226 |
227 |
--------------------------------------------------------------------------------
/docs/libvirt-1.0-Libvirt_Application_Development_Guide_Using_Python-en-US.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/docs/libvirt-1.0-Libvirt_Application_Development_Guide_Using_Python-en-US.pdf
--------------------------------------------------------------------------------
/docs/数据库设计.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/docs/数据库设计.png
--------------------------------------------------------------------------------
/docs/环境部署说明.txt:
--------------------------------------------------------------------------------
1 | 环境部署说明
2 | host安装说明
3 |
4 | 1. host目前选择版本centos7.1
5 |
6 | 2. Host安装包:
7 |
8 | 1) kvm相关包:
9 | yum install qemu-kvm libvirt libvirt-python
10 | 2) python依赖包:
11 | requests、threadpool
12 | 3) 其它rpm包:
13 | util-linux
14 | 3. Disk配置:
15 | 1) 指定1块硬盘,例如/dev/sda,用来存放vm的系统盘;
16 | 2) 格式化,并挂载到/img/os目录;
17 | 3) 指定剩下的N-1块硬盘,用来存放vm的数据盘;(如果硬盘做了raid,则意味着,这个raid盘,用来存放vm的数据盘)
18 | 4) 格式化,并挂载到/img/dataN目录;
19 |
20 | 举例:
21 | 例如一个host有5块盘,sda/sdb/sdc/sdd/sde,则:
22 | 1) 选择sda用来存放vm的系统盘;
23 | 2) 格式化并挂载:
24 | mkfs.ext4 /dev/sda && mount /dev/sda /img/os
25 | 3) 选择sdb/sdc/sdd/sde,用来存放vm的数据盘;
26 | 4) 格式化并挂载:
27 | mkfs.ext4 /dev/sdb && mount /dev/sdb /img/data1
28 | mkfs.ext4 /dev/sdc && mount /dev/sdc /img/data2
29 | mkfs.ext4 /dev/sdd && mount /dev/sdd /img/data3
30 | mkfs.ext4 /dev/sde && mount /dev/sde /img/data4
31 |
32 |
33 | 4. net配置:
34 | 创建一个名叫ovirtmgmt的网桥
35 |
36 | vm安装说明(以centos为例)
37 |
38 | 1. 安装rpm包qemu-guest-agent:
39 | yum install qemu-guest-agent
40 |
41 | 2. 添加开机自启动程序:
42 | killall qemu-ga
43 | nohup qemu-ga -p /dev/virtio-ports/org.qemu.guest_agent.0 &
44 |
--------------------------------------------------------------------------------
/screenshots/任务管理.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/screenshots/任务管理.jpg
--------------------------------------------------------------------------------
/screenshots/添加镜像模板.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/screenshots/添加镜像模板.jpg
--------------------------------------------------------------------------------
/screenshots/登录页.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/screenshots/登录页.jpg
--------------------------------------------------------------------------------
/screenshots/虚拟机列表.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/screenshots/虚拟机列表.jpg
--------------------------------------------------------------------------------
/screenshots/虚拟机快照管理.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/screenshots/虚拟机快照管理.jpg
--------------------------------------------------------------------------------
/screenshots/虚拟机总览.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/screenshots/虚拟机总览.jpg
--------------------------------------------------------------------------------
/screenshots/虚拟机配置.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/screenshots/虚拟机配置.jpg
--------------------------------------------------------------------------------
/screenshots/设备列表页.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/screenshots/设备列表页.jpg
--------------------------------------------------------------------------------
/screenshots/设备总览.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/screenshots/设备总览.jpg
--------------------------------------------------------------------------------
/web/api/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/web/api/__init__.py
--------------------------------------------------------------------------------
/web/api/admin.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | from django.contrib import admin
3 | from api.models import TaskType
4 | from api.models import TaskList
5 | from api.models import AddIns
6 | from api.models import DelIns
7 | from api.models import SnapIns
8 | from api.models import SettingIns
9 | from api.models import CtrlIns
10 | from api.models import AddVmFile
11 | from api.models import SetNetIns
12 |
13 |
14 | class TaskTypeAdmin(admin.ModelAdmin):
15 | list_display = ('type', 'name', 'age', 'failed', )
16 | search_fields = ('type', 'name', 'age', 'failed', ) # 搜索字段
17 | list_filter = ('name', ) # 过滤器
18 |
19 |
20 | class TaskListAdmin(admin.ModelAdmin):
21 | list_display = ('server', 'instance', 'status', 'type',)
22 | search_fields = ('server', 'instance', 'type', 'status', 'group_id') # 搜索字段
23 | list_filter = ('server', 'instance', 'type', 'status', 'group_id') # 过滤器
24 |
25 |
26 | class AddInsAdmin(admin.ModelAdmin):
27 | list_display = ('uuid', 'vm_name', 'vm_file', 'cpu_num', 'mem_size', 'sys_disk_size', 'data_disk_size', )
28 | search_fields = ('vm_name', ) # 搜索字段
29 | list_filter = ('vm_file', ) # 过滤器
30 |
31 |
32 | class DelInsAdmin(admin.ModelAdmin):
33 | list_display = ('uuid', 'del_disk', )
34 | search_fields = ('uuid', 'del_disk', ) # 搜索字段
35 | list_filter = ('del_disk', ) # 过滤器
36 |
37 |
38 | class SnapInsAdmin(admin.ModelAdmin):
39 | list_display = ('uuid', 'snap_name',)
40 | search_fields = ('uuid', 'snap_name', ) # 搜索字段
41 | list_filter = ('snap_name', ) # 过滤器
42 |
43 |
44 | class SettingInsAdmin(admin.ModelAdmin):
45 | list_display = ('uuid', 'new_cpu_num', 'sysdisk_extend', 'datadisk_extend', 'new_mem_size', )
46 | search_fields = ('uuid', 'new_cpu_num', 'sysdisk_extend', 'datadisk_extend', 'new_mem_size', )
47 |
48 |
49 | class CtrlInsAdmin(admin.ModelAdmin):
50 | list_display = ('uuid', 'action', )
51 | search_fields = ('uuid', 'action', ) # 搜索字段
52 | list_filter = ('action', ) # 过滤器
53 |
54 |
55 | class AddVmFileAdmin(admin.ModelAdmin):
56 | list_display = ('uuid', 'uri', 'save_path', 'format', )
57 | search_fields = ('uuid', 'uri', 'save_path', 'format',) # 搜索字段
58 | list_filter = ('format', ) # 过滤器
59 |
60 |
61 | class SetNetInsAdmin(admin.ModelAdmin):
62 | list_display = ('uuid', 'nic_name', 'ip', 'bootproto', 'netmask', 'gateway', 'dns',)
63 | search_fields = ('uuid', 'nic_name', 'ip', 'bootproto', 'netmask', 'gateway', 'dns',) # 搜索字段
64 | list_filter = ('bootproto',) # 过滤器
65 |
66 |
67 | admin.site.register(TaskType, TaskTypeAdmin)
68 | admin.site.register(TaskList, TaskListAdmin)
69 | admin.site.register(AddIns, AddInsAdmin)
70 | admin.site.register(DelIns, DelInsAdmin)
71 | admin.site.register(SnapIns, SnapInsAdmin)
72 | admin.site.register(SettingIns, SettingInsAdmin)
73 | admin.site.register(CtrlIns, CtrlInsAdmin)
74 | admin.site.register(AddVmFile, AddVmFileAdmin)
75 | admin.site.register(SetNetIns, SetNetInsAdmin)
76 |
--------------------------------------------------------------------------------
/web/api/apps.py:
--------------------------------------------------------------------------------
1 | from __future__ import unicode_literals
2 |
3 | from django.apps import AppConfig
4 |
5 |
6 | class ApiConfig(AppConfig):
7 | name = 'api'
8 |
--------------------------------------------------------------------------------
/web/api/migrations/0002_auto_20160608_1532.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.9.5 on 2016-06-08 15:32
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('api', '0001_initial'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterField(
16 | model_name='tasklist',
17 | name='father_id',
18 | field=models.CharField(blank=True, default=None, max_length=32, verbose_name='\u7236\u4efb\u52a1ID'),
19 | ),
20 | migrations.AlterField(
21 | model_name='tasklist',
22 | name='group_id',
23 | field=models.CharField(blank=True, default=None, max_length=32, verbose_name='\u4efb\u52a1\u7ec4ID'),
24 | ),
25 | ]
26 |
--------------------------------------------------------------------------------
/web/api/migrations/0003_auto_20160608_1605.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.9.5 on 2016-06-08 16:05
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('api', '0002_auto_20160608_1532'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterField(
16 | model_name='tasklist',
17 | name='father_id',
18 | field=models.CharField(default=None, max_length=32, null=True, verbose_name='\u7236\u4efb\u52a1ID'),
19 | ),
20 | migrations.AlterField(
21 | model_name='tasklist',
22 | name='group_id',
23 | field=models.CharField(default=None, max_length=32, null=True, verbose_name='\u4efb\u52a1\u7ec4ID'),
24 | ),
25 | ]
26 |
--------------------------------------------------------------------------------
/web/api/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/web/api/migrations/__init__.py
--------------------------------------------------------------------------------
/web/api/models.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | from __future__ import unicode_literals
3 | from django.db import models
4 | import uuid
5 |
6 |
7 | # 任务类型
8 | class TaskType(models.Model):
9 | name = models.CharField(max_length=100, verbose_name='任务名称')
10 | type = models.IntegerField(blank=False, default=0, verbose_name='任务类型号',
11 | help_text="说明: 1-新建虚拟机;2-更新虚拟机配置;3-删除虚拟机;"
12 | "4-虚拟机创建快照;5-虚拟机恢复快照;7-删除快照;"
13 | "8-网卡配置;20-启动/停止虚拟机;40--下载任务;")
14 | age = models.IntegerField(blank=False, default=0, verbose_name='领取有效期(秒)')
15 | failed = models.IntegerField(blank=False, default=0, verbose_name='响应有效期(秒)',
16 | help_text="提示: 1分钟: 60; 5分钟: 300; 10分钟: 600; 半小时: 1800;")
17 |
18 | class Meta:
19 | verbose_name = '任务有效期'
20 | verbose_name_plural = '1-任务类型注册'
21 |
22 | def __unicode__(self):
23 | return u'%s | %s' % (self.type, self.name)
24 |
25 |
26 | class TaskList(models.Model):
27 | server = models.ForeignKey('server.Server', related_name='task_server', verbose_name='任务的关联设备')
28 | instance = models.ForeignKey('instance.Instance', related_name='task_instance', null=True, blank=True,
29 | verbose_name='任务的关联虚拟机', help_text='当没有虚拟机可关联时,值为None')
30 | type = models.ForeignKey('TaskType', related_name='task_type', verbose_name='任务的关联类型')
31 | create_time = models.CharField(verbose_name='创建时间', default='2016-01-01 00:00:00',
32 | max_length=20, help_text='创建时插入当前时间')
33 |
34 | end_time = models.CharField(verbose_name='完成时间', default='2016-01-01 00:00:00',
35 | max_length=20, help_text='创建时插入当前时间')
36 | uuid = models.UUIDField(verbose_name='UUID', primary_key=True, default=uuid.uuid4, editable=False)
37 | group_id = models.CharField(verbose_name='任务组ID', max_length=32, null=True, default=None)
38 | father_id = models.CharField(verbose_name='父任务ID', max_length=32, null=True, default=None)
39 |
40 | status = models.IntegerField(default=0, verbose_name='任务状态',
41 | help_text='0-创建未发布, 1-发布未领取, 2-领取未完成, 3-完成且成功, 4-完成却失败, 5-取消')
42 |
43 | class Meta:
44 | verbose_name = '所有任务清单'
45 | verbose_name_plural = '2-所有任务清单'
46 |
47 | def __unicode__(self):
48 | return u'%s | %s' % (self.instance, self.type)
49 |
50 |
51 | class AddIns(models.Model):
52 | uuid = models.ForeignKey('TaskList', related_name='ai_uuid', verbose_name='任务的关联UUID')
53 | vm_name = models.CharField(verbose_name='虚拟机名称', max_length=30)
54 | vm_file = models.ForeignKey('server.VmFile', related_name='ai_vmfiles', verbose_name='关联VmFile')
55 | cpu_num = models.IntegerField(default=0, verbose_name='CPU(核)')
56 | cpu_model = models.IntegerField(default=1, verbose_name='CPU模式',
57 | help_text='此功能暂时未实现(配方),全部默认为1')
58 | disk_model = models.IntegerField(default=1, verbose_name='数据盘模式',
59 | help_text='此功能暂时未实现(配方),全部默认为1')
60 | sys_disk_size = models.BigIntegerField(default=0, verbose_name='系统盘大小',
61 | help_text='单位: Byte')
62 | data_disk_size = models.BigIntegerField(default=0, verbose_name='数据盘盘大小',
63 | help_text='单位: Byte')
64 | mem_size = models.BigIntegerField(default=0, verbose_name='内存大小',
65 | help_text='单位: Byte')
66 |
67 | class Meta:
68 | verbose_name = '创建虚拟机'
69 | verbose_name_plural = '3-创建虚拟机'
70 |
71 | def __unicode__(self):
72 | return u'%s | %s' % (self.vm_name, self.uuid)
73 |
74 |
75 | class DelIns(models.Model):
76 | uuid = models.ForeignKey('TaskList', related_name='di_uuid', verbose_name='任务的关联UUID')
77 | del_disk = models.IntegerField(default=0, verbose_name='删除数据盘',
78 | help_text='0-删除, 1-不删除')
79 |
80 | class Meta:
81 | verbose_name = '删除虚拟机'
82 | verbose_name_plural = '4-删除虚拟机'
83 |
84 | def __unicode__(self):
85 | return u'%s | %s' % (self.uuid, self.del_disk)
86 |
87 |
88 | class SnapIns(models.Model):
89 | uuid = models.ForeignKey('TaskList', related_name='si_uuid', verbose_name='任务的关联UUID')
90 | snap_name = models.CharField(verbose_name='快照名称', max_length=50)
91 |
92 | class Meta:
93 | verbose_name = '快照相关操作'
94 | verbose_name_plural = '5-快照相关操作'
95 |
96 | def __unicode__(self):
97 | return u'%s | %s' % (self.uuid, self.snap_name)
98 |
99 |
100 | class SettingIns(models.Model):
101 | uuid = models.ForeignKey('TaskList', related_name='si2_uuid', verbose_name='任务的关联UUID')
102 | new_cpu_num = models.IntegerField(verbose_name='新CPU配置(核)')
103 | sysdisk_extend = models.BigIntegerField(default=0, verbose_name='新增系统盘大小',
104 | help_text='单位: Byte')
105 | datadisk_extend = models.BigIntegerField(default=0, verbose_name='新增数据盘盘大小',
106 | help_text='单位: Byte')
107 | new_mem_size = models.BigIntegerField(default=0, verbose_name='新内存大小',
108 | help_text='单位: Byte')
109 |
110 | class Meta:
111 | verbose_name = '虚拟机增加配置'
112 | verbose_name_plural = '6-虚拟机增加配置'
113 |
114 | def __unicode__(self):
115 | return u'%s' % self.uuid
116 |
117 |
118 | class CtrlIns(models.Model):
119 | uuid = models.ForeignKey('TaskList', related_name='ci_uuid', verbose_name='任务的关联UUID')
120 | action = models.CharField(verbose_name='操作', max_length=10)
121 |
122 | class Meta:
123 | verbose_name = '虚拟机开关机'
124 | verbose_name_plural = '7-虚拟机开关机'
125 |
126 | def __unicode__(self):
127 | return u'%s | %s' % (self.uuid, self.action)
128 |
129 |
130 | class AddVmFile(models.Model):
131 | uuid = models.ForeignKey('TaskList', related_name='avf_uuid', verbose_name='任务的关联UUID')
132 |
133 | uri = models.CharField(max_length=1000, default='', verbose_name='下载地址')
134 | size = models.IntegerField(blank=False, default=0, verbose_name='文件大小')
135 | md5 = models.CharField(max_length=45, default='', verbose_name='MD5')
136 | save_path = models.CharField(max_length=45, default='', verbose_name='保存路径')
137 | format = models.IntegerField(blank=False, default=0, verbose_name='文件类型',
138 | help_text='0-iso, 1-qcow2, 3-未知 ')
139 |
140 | class Meta:
141 | verbose_name = '添加镜像文件'
142 | verbose_name_plural = '8-添加镜像文件'
143 |
144 | def __unicode__(self):
145 | return u'%s | %s | %s' % (self.uuid, self.md5, self.format)
146 |
147 |
148 | class SetNetIns(models.Model):
149 | uuid = models.ForeignKey('TaskList', related_name='sni_uuid', verbose_name='任务的关联UUID')
150 | nic_name = models.CharField(max_length=45, verbose_name='网卡名称')
151 | ip = models.CharField(max_length=45, default='', verbose_name='绑定IP')
152 | bootproto = models.CharField(max_length=45, default='', verbose_name='类型')
153 | netmask = models.CharField(max_length=45, default='', verbose_name='子网掩码')
154 | gateway = models.CharField(max_length=45, default='', verbose_name='网关')
155 | dns = models.CharField(max_length=45, default='', verbose_name='DNS')
156 |
157 | class Meta:
158 | verbose_name = '配置网卡'
159 | verbose_name_plural = '9-配置网卡'
160 |
161 | def __unicode__(self):
162 | return u'%s | %s | %s | %s' % (self.uuid, self.ip, self.nic_name, self.bootproto)
163 |
--------------------------------------------------------------------------------
/web/api/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/web/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", "webkvmmgr.settings")
7 |
8 | from django.core.management import execute_from_command_line
9 |
10 | execute_from_command_line(sys.argv)
11 |
--------------------------------------------------------------------------------
/web/server/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/web/server/__init__.py
--------------------------------------------------------------------------------
/web/server/admin.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | from django.contrib import admin
3 | from server.models import Server
4 | from server.models import VmFile
5 | from server.models import IosTemplate
6 | from server.models import SDiskConf
7 | from server.models import SNetConf
8 | from server.models import SBasicStat
9 | from server.models import SDiskStat
10 | from server.models import SNetStat
11 |
12 |
13 | # Register your models here.
14 | class ServerAdmin(admin.ModelAdmin):
15 | list_display = ('sn', 'name', 'alias', 'status', 'refresh', )
16 | search_fields = ('sn', 'islock', 'hv_version', 'libvirt_version', 'status', ) # 搜索字段
17 | list_filter = ('sn', 'islock', 'hv_version', 'libvirt_version', 'status', ) # 过滤器
18 |
19 |
20 | class VmFileAdmin(admin.ModelAdmin):
21 | list_display = ('name', 'server', 'size', 'format', 'source', )
22 | search_fields = ('server', 'name', 'format', 'source', ) # 搜索字段
23 | list_filter = ('server', 'format', 'source', ) # 过滤器
24 |
25 |
26 | class IosTemplateAdmin(admin.ModelAdmin):
27 | list_display = ('name', 'server', 'vm_file', 'comment',)
28 | search_fields = ('server', 'name', 'vm_file',) # 搜索字段
29 | list_filter = ('server', 'vm_file',) # 过滤器
30 |
31 |
32 | class SDiskConfAdmin(admin.ModelAdmin):
33 | list_display = ('server', 'source', 'mounted', 'create_time', 'refresh', )
34 | search_fields = ('server', ) # 搜索字段
35 | list_filter = ('server', ) # 过滤器
36 |
37 |
38 | class SNetConfAdmin(admin.ModelAdmin):
39 | list_display = ('name', 'server', 'create_time', 'refresh', )
40 | search_fields = ('name', 'server', 'create_time', 'refresh', ) # 搜索字段
41 | list_filter = ('name', 'server', ) # 过滤器
42 |
43 |
44 | class SBasicStatAdmin(admin.ModelAdmin):
45 | list_display = ('stat_type', 'server', 'value', 'create_time', )
46 | search_fields = ('stat_type', 'server', ) # 搜索字段
47 | list_filter = ('stat_type', 'server', ) # 过滤器
48 |
49 |
50 | class SDiskStatAdmin(admin.ModelAdmin):
51 | list_display = ('disk_name', 'used', 'util', 'create_time',)
52 | search_fields = ('disk_name', ) # 搜索字段
53 | list_filter = ('disk_name', ) # 过滤器
54 |
55 |
56 | class SNetStatAdmin(admin.ModelAdmin):
57 | list_display = ('net_name', 'net_in', 'net_out', 'create_time', )
58 | search_fields = ('net_name', ) # 搜索字段
59 | list_filter = ('net_name', ) # 过滤器
60 |
61 |
62 | admin.site.register(Server, ServerAdmin)
63 | admin.site.register(VmFile, VmFileAdmin)
64 | admin.site.register(IosTemplate, IosTemplateAdmin)
65 | admin.site.register(SDiskConf, SDiskConfAdmin)
66 | admin.site.register(SNetConf, SNetConfAdmin)
67 | admin.site.register(SBasicStat, SBasicStatAdmin)
68 | admin.site.register(SDiskStat, SDiskStatAdmin)
69 | admin.site.register(SNetStat, SNetStatAdmin)
70 |
--------------------------------------------------------------------------------
/web/server/apps.py:
--------------------------------------------------------------------------------
1 | from __future__ import unicode_literals
2 |
3 | from django.apps import AppConfig
4 |
5 |
6 | class ServerConfig(AppConfig):
7 | name = 'server'
8 |
--------------------------------------------------------------------------------
/web/server/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/web/server/migrations/__init__.py
--------------------------------------------------------------------------------
/web/server/models.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | from __future__ import unicode_literals
3 | from django.db import models
4 |
5 |
6 | # 设备清单
7 | class Server(models.Model):
8 | # 前端配置或计算的
9 | name = models.CharField(max_length=45, default='未知', verbose_name='单位名称')
10 | alias = models.CharField(max_length=45, default='未知', verbose_name='设备别名')
11 | islock = models.IntegerField(default=1, verbose_name='锁定状态',
12 | help_text="0:锁定;1:解锁")
13 |
14 | # 主机硬件配置(host.hw)
15 | architecture = models.CharField(max_length=10, default='未知', verbose_name='系统位数')
16 | version = models.CharField(max_length=10, default='0.0.0', verbose_name='业务包版本')
17 | libvirt_version = models.CharField(max_length=10, default='0.0.0', verbose_name='libvirt版本')
18 | hv_version = models.CharField(max_length=10, default='0.0.0', verbose_name='hypervisor版本')
19 | cpu_name = models.CharField(max_length=100, default='未知', verbose_name='CPU名称')
20 | cpu_num = models.IntegerField(default=0, verbose_name='CPU(核)')
21 | mem_size = models.BigIntegerField(blank=False, default=0, verbose_name='内存总数(Byte)')
22 | disk_size = models.BigIntegerField(blank=False, default=0, verbose_name='磁盘大小(Byte)')
23 | data_disk_num = models.IntegerField(blank=False, default=0, verbose_name='数据盘数量(个)')
24 |
25 | # 主机状态 (host.status)
26 | sn = models.CharField(max_length=13, verbose_name='sn')
27 | refresh = models.DateTimeField(blank=False, null=True, verbose_name='刷新时间',
28 | help_text="用于判断设备是否失联,根据设备的host_status反馈来更新")
29 | ip = models.GenericIPAddressField(max_length=15, default='0.0.0.0', verbose_name='出口IP')
30 | status = models.IntegerField(default=0, verbose_name='状态',
31 | help_text='(1--在线; 0--关机; 2--前端显示(失联),刷新时间超过一小时)')
32 |
33 | class Meta:
34 | verbose_name = '设备清单'
35 | verbose_name_plural = '1-设备列表'
36 |
37 | def __unicode__(self):
38 | return u'%s' % self.sn
39 |
40 |
41 | # --------- 配置相关
42 | # 设备VM Files表
43 | class VmFile(models.Model):
44 | server = models.ForeignKey('Server', related_name='vf_server', verbose_name='VM File的关联设备')
45 | name = models.CharField(max_length=100, verbose_name='VM镜像名称')
46 | size = models.BigIntegerField(default=0, verbose_name='镜像大小',
47 | help_text='单位: byte')
48 | format = models.IntegerField(verbose_name='镜像类型',
49 | help_text='说明: 0--iso;1--qcow2; 2--未知;')
50 | source = models.IntegerField(verbose_name='镜像文件来源',
51 | help_text='说明: 0--设备预装 or FTP添加并下载完成; 1--FTP添加未下载; 2--未知;')
52 | path = models.CharField(verbose_name='镜像保存路经', max_length=50,
53 | help_text='一般是服务端配置的模板路径和镜像路径')
54 | comment = models.TextField(verbose_name='备注信息')
55 |
56 | class Meta:
57 | verbose_name = '设备VM Files表'
58 | verbose_name_plural = '2-设备VM Files表'
59 |
60 | def __unicode__(self):
61 | return u'%s' % self.name
62 |
63 |
64 | # 设备镜像配置模板表
65 | class IosTemplate(models.Model):
66 | server = models.ForeignKey('Server', related_name='it_server', verbose_name='镜像模板的关联设备')
67 | name = models.CharField(max_length=100, verbose_name='VM模板镜像名称')
68 | vm_file = models.ForeignKey('VmFile', related_name='vm_files', verbose_name='关联VmFile')
69 | cpu_num = models.IntegerField(default=0, verbose_name='CPU(核)')
70 | cpu_model = models.IntegerField(default=1, verbose_name='CPU模式',
71 | help_text='此功能暂时未实现(配方),全部默认为1')
72 | disk_model = models.IntegerField(default=1, verbose_name='数据盘模式',
73 | help_text='此功能暂时未实现(配方),全部默认为1')
74 | sys_disk_size = models.BigIntegerField(default=0, verbose_name='系统盘大小',
75 | help_text='单位: Byte')
76 | data_disk_size = models.BigIntegerField(default=0, verbose_name='数据盘盘大小',
77 | help_text='单位: Byte')
78 | mem_size = models.BigIntegerField(default=0, verbose_name='内存大小',
79 | help_text='单位: Byte')
80 | comment = models.TextField(verbose_name='备注信息')
81 |
82 | class Meta:
83 | verbose_name = '设备镜像配置模板表'
84 | verbose_name_plural = '3-设备镜像配置模板表'
85 |
86 | def __unicode__(self):
87 | return u'%s' % self.name
88 |
89 |
90 | # 磁盘配置
91 | class SDiskConf(models.Model):
92 | server = models.ForeignKey('Server', related_name='sdc_server', verbose_name='磁盘配置的关联设备')
93 | create_time = models.DateTimeField(verbose_name='创建时间',
94 | help_text='该配置创建的时间')
95 | refresh = models.DateTimeField(verbose_name='创建时间',
96 | help_text='目的是确定该配置失效的时间')
97 | source = models.CharField(max_length=100, verbose_name='源数据盘')
98 | total_size = models.BigIntegerField(default=0, verbose_name='总大小',
99 | help_text='单位: Byte')
100 | mounted = models.CharField(max_length=100, verbose_name='挂载路径')
101 |
102 | class Meta:
103 | verbose_name = '设备磁盘配置'
104 | verbose_name_plural = '4-设备设备磁盘配置'
105 |
106 | def __unicode__(self):
107 | return u'%s | %s' % (self.source, self.mounted)
108 |
109 |
110 | # 网卡配置
111 | class SNetConf(models.Model):
112 | server = models.ForeignKey('Server', related_name='snc_server', verbose_name='网卡配置的关联设备')
113 | create_time = models.DateTimeField(verbose_name='创建时间',
114 | help_text='该配置创建的时间')
115 | refresh = models.DateTimeField(verbose_name='创建时间',
116 | help_text='目的是确定该配置失效的时间')
117 | name = models.CharField(verbose_name='网卡名称', max_length=30)
118 | net_type = models.CharField(verbose_name='网卡类型', max_length=20,
119 | help_text='说明: monitor-镜像网卡; server-服务网卡')
120 |
121 | class Meta:
122 | verbose_name = '设备网卡配置'
123 | verbose_name_plural = '5-设备网卡配置'
124 |
125 | def __unicode__(self):
126 | return u'%s | %s' % (self.name, self.net_type)
127 |
128 |
129 | # ------- 状态相关
130 | # 设备基础状态信息表
131 | class SBasicStat(models.Model):
132 | server = models.ForeignKey('Server', related_name='sbs_server', verbose_name='基础状态的关联设备')
133 | create_time = models.DateTimeField(verbose_name='时间')
134 | stat_type = models.CharField(verbose_name='状态类型', max_length=10,
135 | help_text='选项,cpu_used, disk_used, mem_used')
136 | value = models.FloatField(default=0, verbose_name='百分比',
137 | help_text='保留两位小数')
138 |
139 | class Meta:
140 | verbose_name = '基础状态信息表'
141 | verbose_name_plural = '6-基础状态信息表'
142 |
143 | def __unicode__(self):
144 | return u'%s' % self.stat_type
145 |
146 |
147 | # 设备磁盘状态详情表
148 | class SDiskStat(models.Model):
149 | disk_name = models.ForeignKey('SDiskConf', related_name='sds_disk', verbose_name='关联的磁盘配置')
150 | create_time = models.DateTimeField(verbose_name='时间',
151 | help_text='数值和DiskConf里refresh一致')
152 | used = models.FloatField(default=0, verbose_name='使用率',
153 | help_text='保留两位小数')
154 | util = models.FloatField(default=0, verbose_name='磁盘Util',
155 | help_text='保留两位小数')
156 |
157 | class Meta:
158 | verbose_name = '磁盘状态详情表'
159 | verbose_name_plural = '7-磁盘状态详情表'
160 |
161 | def __unicode__(self):
162 | return u'%s | %s' % (self.used, self.util)
163 |
164 |
165 | # 设备网络状态详情表
166 | class SNetStat(models.Model):
167 | net_name = models.ForeignKey('SNetConf', related_name='sns_net', verbose_name='关联的网络配置')
168 | create_time = models.DateTimeField(verbose_name='时间',
169 | help_text='数值和DiskConf里refresh一致')
170 | net_in = models.BigIntegerField(default=0, verbose_name='入口流量',
171 | help_text='单位: KBps')
172 | net_out = models.BigIntegerField(default=0, verbose_name='出口流量',
173 | help_text='单位: KBps')
174 |
175 | class Meta:
176 | verbose_name = '网络状态详情表'
177 | verbose_name_plural = '8-网络状态详情表'
178 |
179 | def __unicode__(self):
180 | return u'%s | %s' % (self.net_in, self.net_out)
181 |
--------------------------------------------------------------------------------
/web/server/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/web/server/views.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | from django.contrib.auth.decorators import login_required
3 | from django.shortcuts import render_to_response, render
4 | from api.models import TaskList
5 | from instance.models import Instance
6 | from server.models import Server, SBasicStat
7 | from server.models import IosTemplate
8 | from server.models import VmFile
9 | from django.db.models import Q
10 | import json
11 |
12 |
13 | # Create your views here.
14 | @login_required
15 | def server_list(request):
16 | errors = list([])
17 | if request.method == 'GET':
18 | order_by = request.GET.get('order_by', 'sn')
19 | sort = request.GET.get('sort', 'up')
20 | word = request.GET.get('word', '')
21 |
22 | if sort == 'down':
23 | new_sort = 'up'
24 | order_str = '-' + order_by
25 | else:
26 | new_sort = 'down'
27 | order_str = order_by
28 |
29 | try:
30 | word = json.loads(word)
31 | except:
32 | word = word
33 |
34 | all_servers = Server.objects.all().count()
35 | online_servers = Server.objects.filter(status=1).count()
36 |
37 | if '' == word:
38 | hosts_info = Server.objects.filter().order_by(order_str)
39 | elif isinstance(word, int):
40 | hosts_info = Server.objects.filter(status=word).order_by(order_str)
41 | else:
42 | hosts_info = Server.objects.filter(
43 | Q(sn=word) | Q(name__contains=word) | Q(alias__contains=word)
44 | ).order_by(order_str)
45 |
46 | return render(request, 'server/server_list.html',
47 | {
48 | 'sort': new_sort,
49 | 'word': word,
50 | 'all_servers': all_servers,
51 | 'online_servers': online_servers,
52 | 'hosts_info': hosts_info
53 | })
54 | else:
55 | errors.append('你咋发的不是GET, 搞笑啊!!!')
56 | return render(request, '444.html', {'errors': errors})
57 |
58 |
59 | @login_required
60 | def server_info(request, sn, tab):
61 | data = list([])
62 | iostemp_list = list([])
63 | vm_files_list = list([])
64 |
65 | errors = list([])
66 | if request.method == 'GET':
67 | if Server.objects.filter(sn=sn).count():
68 | name = Server.objects.get(sn=sn).name
69 | if tab != 'packages':
70 | iostemp_list = IosTemplate.objects.filter(server__sn=sn)
71 | else:
72 | vm_files_list = VmFile.objects.filter(server__sn=sn)
73 |
74 | if tab == 'logs':
75 | data.append('logs')
76 | elif tab == 'instances':
77 | data = Instance.objects.filter(server__sn=sn)
78 | elif tab == 'tasks_all':
79 | data.append(TaskList.objects.order_by('-create_time').filter(server__sn=sn))
80 | data.append(['创建未发布', '发布未领取', '领取未完成', '完成且成功', '完成却失败', '取消'])
81 | elif tab == 'tasks':
82 | # data[0] 创建未发布任务清单
83 | data.append(TaskList.objects.order_by('-create_time').filter(server__sn=sn, status=0))
84 |
85 | # data[1] 发布未领取任务清单
86 | data.append(TaskList.objects.order_by('-create_time').filter(server__sn=sn, status=1))
87 |
88 | # data[2] 领取处理中任务清单
89 | data.append(TaskList.objects.order_by('-create_time').filter(server__sn=sn, status=2))
90 |
91 | # data[3] 取消任务清单
92 | data.append(TaskList.objects.order_by('-create_time').filter(server__sn=sn, status=5))
93 |
94 | # data[4] 领取已完成任务清单
95 | data.append(TaskList.objects.order_by('-create_time').filter(Q(server__sn=sn), Q(status=3) | Q(status=4)))
96 |
97 | elif tab == 'setting':
98 | data.append('setting')
99 | elif tab == 'packages':
100 | data = IosTemplate.objects.filter(server__sn=sn)
101 | else:
102 | tab = 'overview'
103 | # ------ 顶部状态
104 | # 服务器基本信息 data[0]
105 | data.append(Server.objects.get(sn=sn))
106 |
107 | # 服务器最近的状态信息 data[1]
108 | basic_stat = dict({})
109 | try:
110 | basic_stat['cpu'] = SBasicStat.objects.filter(server__sn=sn, stat_type='cpu_used').last().value
111 | except:
112 | basic_stat['cpu'] = 0
113 | try:
114 | basic_stat['disk'] = SBasicStat.objects.filter(server__sn=sn, stat_type='disk_used').last().value
115 | except:
116 | basic_stat['disk'] = 0
117 | try:
118 | basic_stat['mem'] = SBasicStat.objects.filter(server__sn=sn, stat_type='mem_used').last().value
119 | except:
120 | basic_stat['mem'] = 0
121 |
122 | # 在线虚拟机数量
123 | basic_stat['runserver'] = Instance.objects.filter(status=1, server__sn=sn).count()
124 | data.append(basic_stat)
125 |
126 | # ------ 业务详情
127 | # VM_files详情 data[2]
128 | vm_files = VmFile.objects.filter(server__sn=sn)
129 | data.append(vm_files)
130 |
131 | # 任务详情 data[3]
132 | task_info = dict({})
133 | task_info["task0"] = TaskList.objects.filter(server__sn=sn, status=0).count()
134 | task_info["task1"] = TaskList.objects.filter(server__sn=sn, status=1).count()
135 | task_info["task2"] = TaskList.objects.filter(server__sn=sn, status=2).count()
136 | task_info["task3"] = TaskList.objects.filter(server__sn=sn, status=3).count()
137 | task_info["task4"] = TaskList.objects.filter(server__sn=sn, status=4).count()
138 | task_info["task5"] = TaskList.objects.filter(server__sn=sn, status=5).count()
139 | data.append(task_info)
140 |
141 | return render(request, 'server/server_info.html',
142 | {'name': name,
143 | 'sn': sn,
144 | 'tab': tab,
145 | 'data': data,
146 | 'iostemp_list': iostemp_list,
147 | 'vm_files_list': vm_files_list
148 | })
149 | else:
150 | return render_to_response('444.html', {'errors': ['SN不存在']})
151 | else:
152 | errors.append('你咋发的不是GET, 搞笑啊!!!')
153 | return render(request, '444.html', {'errors': errors})
--------------------------------------------------------------------------------
/web/templates/444.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 | {% load staticfiles %}
3 | {% block title %}Ooo~~(╯﹏╰)b....{% endblock %}
4 | {% block content %}
5 |
6 |
7 |
8 |
Oops!
9 |
10 |
Ooo~~(╯﹏╰)b....
11 | {% if errors %}
12 |
13 | {% for error in errors %}
14 | - {{ error }}
15 | {% endfor %}
16 |
17 | {% endif %}
18 |
出现了超级奇葩的错误,你联系Crazw吧!
19 |
← Back
20 |
21 |
22 |
23 | {% endblock %}
24 |
--------------------------------------------------------------------------------
/web/templates/api_error.html:
--------------------------------------------------------------------------------
1 | {% for error in errors %}
2 | {{ error }}
3 | {% endfor %}
--------------------------------------------------------------------------------
/web/templates/base.html:
--------------------------------------------------------------------------------
1 | {% load staticfiles %}
2 |
3 |
4 |
5 |
6 |
7 | {% block title %}{% endblock %}
8 |
9 |
10 |
11 |
12 | {% block style %}{% endblock %}
13 |
14 |
15 |
16 |
17 |
18 |
19 |
32 |
33 |
34 |
41 |
42 |
43 |
44 |
45 | {% if request.user.is_authenticated or user.is_authenticated %}
46 | -
47 |
48 |
49 |
50 |
51 | -
52 |
53 |
54 | {% endif %}
55 |
56 |
57 |
58 |
59 |
60 |
61 | {% block content %}{% endblock %}
62 |
63 |
64 |
65 | {% block script %}{% endblock %}
66 |
67 |
68 |
--------------------------------------------------------------------------------
/web/templates/basic_modal.html:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/web/templates/basic_task_modal.html:
--------------------------------------------------------------------------------
1 |
2 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/web/templates/create_ins_modal.html:
--------------------------------------------------------------------------------
1 |
2 |
56 |
57 |
--------------------------------------------------------------------------------
/web/templates/login.html:
--------------------------------------------------------------------------------
1 | {% load staticfiles %}
2 |
3 |
4 |
5 |
6 |
7 |
8 | {# #}
9 |
10 | o(≧v≦)o~~好棒!登录吧!
11 |
12 |
13 |
14 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/web/templates/server/instances.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 名称 |
5 | 状态 |
6 | 内核版本 |
7 | CPUs |
8 | 内存 |
9 | 磁盘 |
10 | 刷新时间 |
11 | 操作 |
12 | 其他 |
13 |
14 |
15 |
16 | {% for item in data %}
17 |
18 | {{ sn }} |
19 | {{ item.name }} |
20 |
21 | {% if item.status == 1 %}
22 | 运行
23 | {% elif item.status == 5 %}
24 | 关机
25 | {% else %}
26 | 配置调整中
27 | {% endif %}
28 | |
29 | {{ item.kernel }} |
30 | {{ item.cpu_num }}核 |
31 | {% widthratio item.mem_size 1048576 1 %}MB |
32 | {% widthratio item.disk_size 1073741824 1 %}GB |
33 | {{ item.refresh | date:'Y-m-d H:i:s' }} |
34 |
35 |
42 |
43 |
44 |
45 |
52 |
53 |
54 |
55 |
62 |
63 |
64 | |
65 |
66 |
67 |
68 | 查看
69 |
70 |
71 | 安装
72 |
73 |
74 | 配置
75 |
76 |
83 | 删除
84 |
85 | |
86 |
87 | {% endfor %}
88 |
89 |
90 | {% include 'basic_task_modal.html' %}
91 |
--------------------------------------------------------------------------------
/web/templates/server/logs.html:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/web/templates/server/logs.html
--------------------------------------------------------------------------------
/web/templates/server/modal_add_iostemp.html:
--------------------------------------------------------------------------------
1 |
2 |
126 |
127 |
--------------------------------------------------------------------------------
/web/templates/server/modal_add_vmfile.html:
--------------------------------------------------------------------------------
1 |
2 |
86 |
87 |
--------------------------------------------------------------------------------
/web/templates/server/packages.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 名称 |
5 | VM模板镜像名称 |
6 | CPUs |
7 | CPU模式 |
8 | 系统盘大小 |
9 | 数据盘大小 |
10 | 磁盘模式 |
11 | 内存 |
12 | 备注 |
13 | 操作 |
14 |
15 |
16 |
17 | {% for item in data %}
18 |
19 | {{ sn }} |
20 | {{ item.id }} |
21 | {{ item.name }} |
22 | {{ item.vm_file }} |
23 | {{ item.cpu_num }}核 |
24 | {{ item.cpu_model }} |
25 | {% widthratio item.sys_disk_size 1073741824 1 %}GB |
26 | {% widthratio item.data_disk_size 1073741824 1 %}GB |
27 | {{ item.disk_model }} |
28 | {% widthratio item.mem_size 1048576 1 %}MB |
29 | {{ item.comment }} |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | |
39 |
40 | {% endfor %}
41 |
42 |
43 |
44 | {% include 'server/modal_add_iostemp.html' %}
45 |
46 |
--------------------------------------------------------------------------------
/web/templates/server/server_list.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 | {% load staticfiles %}
3 | {% block title %} 设备清单 - FxData{% endblock %}
4 | {% block style %}
5 |
6 |
7 | {% endblock %}
8 | {% block content %}
9 |
10 |
11 |
12 |
13 |
14 |
设备列表
15 |
在线设备:{{ online_servers }}/{{ all_servers }}
16 |
34 |
35 |
36 |
37 |
38 | {% if hosts_info %}
39 |
111 | {% else %}
112 |
113 |
114 |
Oops. Ooo~~(╯﹏╰)b....
115 | No device found! So Bad!!!
116 |
117 |
118 | {% endif %}
119 |
120 |
121 |
122 |
123 | {% include 'basic_modal.html' %}
124 |
125 |
126 | {% endblock %}
127 |
128 | {% block script %}
129 |
130 |
131 |
160 | {% endblock %}
161 |
--------------------------------------------------------------------------------
/web/templates/server/setting.html:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/web/templates/server/setting.html
--------------------------------------------------------------------------------
/web/templates/server/tasks-all.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
操作日志任务状态说明: 0-创建未发布, 1-发布未领取, 2-领取未完成, 3-完成且成功, 4-完成却失败, 5-取消
5 |
6 |
7 |
8 | {% for item in data.0 %}
9 | -
10 |
11 |
12 |
{{ item.type.name }}
13 | {% if item.end_time == '2016-01-01 00:00:00' %}
14 |
{{ item.create_time }}
15 | {% else %}
16 |
完成
17 |
{{ item.create_time }} - {{ item.end_time }}
18 | {% endif %}
19 |
34 |
35 |
36 | {% endfor %}
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/web/templates/server/tasks.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 最近完成查看全部
6 |
7 |
8 | {% for item in data.1 %}
9 | -
10 |
11 |
19 |
20 | {% endfor %}
21 | -
22 |
23 |
释放公网IP
24 |
1秒之内
25 |
2016-05-07 12:38:55
26 |
29 |
30 |
31 | -
32 |
33 |
释放公网IP
34 |
1秒之内
35 |
2016-05-07 12:38:55
36 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/web/templates/side_base.html:
--------------------------------------------------------------------------------
1 | {% extends "base.html" %}
2 | {% block content %}
3 |
4 |
5 |
6 |
47 |
48 | {% block right_content %}{% endblock %}
49 |
50 |
51 |
52 | {% endblock %}
53 |
--------------------------------------------------------------------------------
/web/webkvmmgr/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/web/webkvmmgr/__init__.py
--------------------------------------------------------------------------------
/web/webkvmmgr/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for webkvmmgr project.
3 |
4 | Generated by 'django-admin startproject' using Django 1.9.5.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/1.9/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/1.9/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/1.9/howto/deployment/checklist/
21 |
22 | # SECURITY WARNING: keep the secret key used in production secret!
23 | SECRET_KEY = '#f_dbl37%^saza4pd33b)v01bxa5bw!rb=0^sj9waco@_^g)!-'
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 | 'server',
41 | 'instance',
42 | 'api',
43 | ]
44 |
45 | MIDDLEWARE_CLASSES = [
46 | 'django.middleware.security.SecurityMiddleware',
47 | 'django.contrib.sessions.middleware.SessionMiddleware',
48 | 'django.middleware.common.CommonMiddleware',
49 | # 'django.middleware.csrf.CsrfViewMiddleware',
50 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
51 | 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
52 | 'django.contrib.messages.middleware.MessageMiddleware',
53 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
54 | ]
55 |
56 | ROOT_URLCONF = 'webkvmmgr.urls'
57 |
58 | TEMPLATES = [
59 | {
60 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
61 | 'DIRS': [os.path.join(BASE_DIR, 'templates')]
62 | ,
63 | 'APP_DIRS': True,
64 | 'OPTIONS': {
65 | 'context_processors': [
66 | 'django.template.context_processors.debug',
67 | 'django.template.context_processors.request',
68 | 'django.contrib.auth.context_processors.auth',
69 | 'django.contrib.messages.context_processors.messages',
70 | ],
71 | },
72 | },
73 | ]
74 |
75 | WSGI_APPLICATION = 'webkvmmgr.wsgi.application'
76 |
77 |
78 | # Database
79 | # https://docs.djangoproject.com/en/1.9/ref/settings/#databases
80 |
81 | # DATABASES = {
82 | # 'default': {
83 | # 'ENGINE': 'django.db.backends.sqlite3',
84 | # 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
85 | # }
86 | # }
87 |
88 | DATABASES = {
89 | 'default': {
90 | 'ENGINE': 'django.db.backends.mysql',
91 | 'NAME': 'fxkvm',
92 | 'USER': 'root',
93 | 'PASSWORD': 'jia0926',
94 | 'HOST': '/Applications/MAMP/tmp/mysql/mysql.sock'
95 | }
96 | }
97 | #
98 | # DATABASES = {
99 | # 'default': {
100 | # 'ENGINE': 'django.db.backends.mysql',
101 | # 'NAME': 'fxkvm',
102 | # 'USER': 'root',
103 | # 'PASSWORD': '0rd1230ac',
104 | # 'HOST': '192.168.1.225',
105 | # 'PORT': '3306',
106 | # }
107 | # }
108 |
109 |
110 | # Password validation
111 | # https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators
112 |
113 | AUTH_PASSWORD_VALIDATORS = [
114 | {
115 | 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
116 | },
117 | {
118 | 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
119 | },
120 | {
121 | 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
122 | },
123 | {
124 | 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
125 | },
126 | ]
127 |
128 |
129 | # Internationalization
130 | # https://docs.djangoproject.com/en/1.9/topics/i18n/
131 |
132 | LANGUAGE_CODE = 'zh-cn'
133 |
134 | TIME_ZONE = 'Asia/Shanghai'
135 |
136 | USE_I18N = True
137 |
138 | USE_L10N = True
139 |
140 | USE_TZ = True
141 |
142 |
143 | # Static files (CSS, JavaScript, Images)
144 | # https://docs.djangoproject.com/en/1.9/howto/static-files/
145 |
146 | STATIC_URL = '/static/'
147 |
148 | STATICFILES_DIRS = (
149 | [os.path.join(BASE_DIR, "webkvmmgr/static")]
150 | )
151 |
152 | # Fix "RuntimeWarning: DateTimeField received a naive datetime" ERROR!!!!
153 | USE_TZ = False
154 |
--------------------------------------------------------------------------------
/web/webkvmmgr/static/css/bootstrap-switch.min.css:
--------------------------------------------------------------------------------
1 | /* ========================================================================
2 | * bootstrap-switch - v3.3.2
3 | * http://www.bootstrap-switch.org
4 | * ========================================================================
5 | * Copyright 2012-2013 Mattia Larentis
6 | *
7 | * ========================================================================
8 | * Licensed under the Apache License, Version 2.0 (the "License");
9 | * you may not use this file except in compliance with the License.
10 | * You may obtain a copy of the License at
11 | *
12 | * http://www.apache.org/licenses/LICENSE-2.0
13 | *
14 | * Unless required by applicable law or agreed to in writing, software
15 | * distributed under the License is distributed on an "AS IS" BASIS,
16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 | * See the License for the specific language governing permissions and
18 | * limitations under the License.
19 | * ========================================================================
20 | */
21 |
22 | .bootstrap-switch{display:inline-block;direction:ltr;cursor:pointer;border-radius:4px;border:1px solid #ccc;position:relative;text-align:left;overflow:hidden;line-height:8px;z-index:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:middle;-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;-o-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.bootstrap-switch .bootstrap-switch-container{display:inline-block;top:0;border-radius:4px;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.bootstrap-switch .bootstrap-switch-handle-off,.bootstrap-switch .bootstrap-switch-handle-on,.bootstrap-switch .bootstrap-switch-label{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;cursor:pointer;display:inline-block!important;height:100%;padding:6px 12px;font-size:14px;line-height:20px}.bootstrap-switch .bootstrap-switch-handle-off,.bootstrap-switch .bootstrap-switch-handle-on{text-align:center;z-index:1}.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-primary,.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-primary{color:#fff;background:#337ab7}.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-info,.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-info{color:#fff;background:#5bc0de}.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-success,.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-success{color:#fff;background:#5cb85c}.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-warning,.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-warning{background:#f0ad4e;color:#fff}.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-danger,.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-danger{color:#fff;background:#d9534f}.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-default,.bootstrap-switch .bootstrap-switch-handle-on.bootstrap-switch-default{color:#000;background:#eee}.bootstrap-switch .bootstrap-switch-label{text-align:center;margin-top:-1px;margin-bottom:-1px;z-index:100;color:#333;background:#fff}.bootstrap-switch .bootstrap-switch-handle-on{border-bottom-left-radius:3px;border-top-left-radius:3px}.bootstrap-switch .bootstrap-switch-handle-off{border-bottom-right-radius:3px;border-top-right-radius:3px}.bootstrap-switch input[type=radio],.bootstrap-switch input[type=checkbox]{position:absolute!important;top:0;left:0;margin:0;z-index:-1;opacity:0;filter:alpha(opacity=0)}.bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-mini .bootstrap-switch-label{padding:1px 5px;font-size:12px;line-height:1.5}.bootstrap-switch.bootstrap-switch-small .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-small .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-small .bootstrap-switch-label{padding:5px 10px;font-size:12px;line-height:1.5}.bootstrap-switch.bootstrap-switch-large .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-large .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-large .bootstrap-switch-label{padding:6px 16px;font-size:18px;line-height:1.3333333}.bootstrap-switch.bootstrap-switch-disabled,.bootstrap-switch.bootstrap-switch-indeterminate,.bootstrap-switch.bootstrap-switch-readonly{cursor:default!important}.bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-disabled .bootstrap-switch-label,.bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-indeterminate .bootstrap-switch-label,.bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-handle-off,.bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-handle-on,.bootstrap-switch.bootstrap-switch-readonly .bootstrap-switch-label{opacity:.5;filter:alpha(opacity=50);cursor:default!important}.bootstrap-switch.bootstrap-switch-animate .bootstrap-switch-container{-webkit-transition:margin-left .5s;-o-transition:margin-left .5s;transition:margin-left .5s}.bootstrap-switch.bootstrap-switch-inverse .bootstrap-switch-handle-on{border-radius:0 3px 3px 0}.bootstrap-switch.bootstrap-switch-inverse .bootstrap-switch-handle-off{border-radius:3px 0 0 3px}.bootstrap-switch.bootstrap-switch-focused{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.bootstrap-switch.bootstrap-switch-inverse.bootstrap-switch-off .bootstrap-switch-label,.bootstrap-switch.bootstrap-switch-on .bootstrap-switch-label{border-bottom-right-radius:3px;border-top-right-radius:3px}.bootstrap-switch.bootstrap-switch-inverse.bootstrap-switch-on .bootstrap-switch-label,.bootstrap-switch.bootstrap-switch-off .bootstrap-switch-label{border-bottom-left-radius:3px;border-top-left-radius:3px}
--------------------------------------------------------------------------------
/web/webkvmmgr/static/css/common.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 |
3 | /**
4 | *
5 | * @authors Crazw (craazw@gmail.com)
6 | * @date 2016-05-16 14:04:42
7 | *
8 | */
9 |
10 | /* 表格字体居中 */
11 | table tr th,td {
12 | text-align: center;
13 | }
14 |
15 | /* 左侧导航栏 */
16 | .sidebar {
17 | position: fixed;
18 | top: 51px;
19 | bottom: 0;
20 | left: 0;
21 | z-index: 1000;
22 | display: block;
23 | padding: 20px;
24 | overflow-x: hidden;
25 | overflow-y: auto;
26 | background-color: #ddd;
27 | border-right: 1px solid #eee;
28 | }
29 |
30 | .nav-sidebar {
31 | margin-right: -21px;
32 | margin-bottom: 20px;
33 | margin-left: -20px;
34 | }
35 |
36 | .nav-sidebar > li > a {
37 | padding-right: 20px;
38 | padding-left: 20px;
39 | }
40 |
41 | .nav-sidebar > .active > a,
42 | .nav-sidebar > .active > a:hover,
43 | .nav-sidebar > .active > a:focus {
44 | color: #fff;
45 | background-color: #428bca;
46 | }
47 |
48 | .main {
49 | padding: 20px;
50 | }
51 |
52 | .main .page-header {
53 | margin-top: 0;
54 | }
55 |
56 | .table-cst-header {
57 | background:red;
58 | }
59 |
60 | /* 设备详情里面的tab样式 */
61 | .inst-bg-btn {
62 | width: 200px;
63 | text-align: center;
64 | }
65 |
66 | .inst-sm-btn {
67 | width: 100;
68 | text-align: center;
69 | }
70 |
71 | /* 必填字段提示的红点*/
72 | /* http://stackoverflow.com/questions/23141854/adding-asterisk-to-required-fields-in-bootstrap-3 */
73 | .form-group.required .control-label:after {
74 | color: #d00;
75 | content: "*";
76 | position: absolute;
77 | margin-left: 8px;
78 | top:7px;
79 | }
80 |
81 |
--------------------------------------------------------------------------------
/web/webkvmmgr/static/css/instance.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/web/webkvmmgr/static/css/instance.css
--------------------------------------------------------------------------------
/web/webkvmmgr/static/css/login.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 | {% load staticfiles %}
3 | /**
4 | *
5 | * @authors Crazw (craazw@gmail.com)
6 | * @date 2016-05-16 14:04:42
7 | *
8 | */
9 |
10 | body {
11 | display: -webkit-box;
12 | display: flex;
13 | flex-flow: column;
14 | min-height: 100%;
15 | background-color: #F6F6F6;
16 | font-family: "PingFang SC", 'Lucica Grande', 'Helvatica', 'Helvatica Neue', 'Hiragino Sans GB', 'Microsoft YaHei', 'WenQuanYi Micro Hei', Arial, serif;
17 | font-size: 14px;
18 | color: #333333;
19 | }
20 |
21 | body.login {
22 | background-image: url(/static/images/bg.png);
23 | background-size: cover;
24 | }
25 |
26 | ._1MGhWz1fBfY5yOL5WHk74Y {
27 | position: relative;
28 | width: 460px;
29 | height: 550px;
30 | margin: 0 auto;
31 | background-image: url(/static/images/main.png);
32 | color: #fff;
33 | }
34 |
35 | ._1MGhWz1fBfY5yOL5WHk74Y .warn {
36 | position: absolute;
37 | top: 220px;
38 | width: 100%;
39 | background: hsla(0,0%,100%,.7);
40 | color: red;
41 | text-align: center;
42 | font-size: 16px;
43 | font-weight: 700;
44 | }
45 |
46 | ._1MGhWz1fBfY5yOL5WHk74Y button {
47 | width: 100%;
48 | height: 44px;
49 | border-radius: 3px;
50 | border: none;
51 | background-color: #0f81c7;
52 | font-size: 18px;
53 | color: #fff;
54 | cursor: pointer;
55 | }
56 |
57 | ._1MGhWz1fBfY5yOL5WHk74Y .input-container input[type=password], ._1MGhWz1fBfY5yOL5WHk74Y .input-container input[type=text] {
58 | width: 100%;
59 | height: 44px;
60 | padding-left: 64px;
61 | border-radius: 3px;
62 | border: none;
63 | background-color: #fff;
64 | font: 18px HiraginoSansGB,Microsoft YaHei;
65 | }
66 |
67 | * {
68 | margin: 0;
69 | padding: 0;
70 | box-sizing: border-box;
71 | }
72 |
73 | ._1MGhWz1fBfY5yOL5WHk74Y .logo {
74 | width: 90px;
75 | height: 19px;
76 | margin: 21px 0 4px 30px;
77 | background-image: url(/static/images/logo.png);
78 | text-indent: -9999px;
79 | }
80 |
81 | ._1MGhWz1fBfY5yOL5WHk74Y .title {
82 | margin: 90px 0 96px;
83 | text-align: center;
84 | font: 50px STHeitiSC-Medium,Microsoft YaHei;
85 | }
86 |
87 | ._1MGhWz1fBfY5yOL5WHk74Y .form-row {
88 | width: 300px;
89 | margin: 0 auto 14px;
90 | }
91 |
92 | ._1MGhWz1fBfY5yOL5WHk74Y .input-container {
93 | position: relative;
94 | }
95 |
96 |
97 | ._1MGhWz1fBfY5yOL5WHk74Y .username {
98 | margin-bottom: 2px;
99 | }
100 |
101 | ._1MGhWz1fBfY5yOL5WHk74Y .input-container.username-container:after {
102 | background-image: url(/static/images/username.svg);
103 | }
104 |
105 | ._1MGhWz1fBfY5yOL5WHk74Y .input-container.password-container:after {
106 | background-image: url(/static/images/password.svg);
107 | }
108 |
109 | ._1MGhWz1fBfY5yOL5WHk74Y .input-container.username-container:after {
110 | width: 18px;
111 | height: 18px;
112 | }
113 |
114 | ._1MGhWz1fBfY5yOL5WHk74Y .input-container.password-container:after {
115 | width: 17px;
116 | height: 20px;
117 | }
118 |
119 | ._1MGhWz1fBfY5yOL5WHk74Y .input-container:after {
120 | content: ' ';
121 | position: absolute;
122 | top: 14px;
123 | left: 25px;
124 | }
125 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/web/webkvmmgr/static/css/server.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 | /**
3 | *
4 | * @authors Crazw (craazw@gmail.com)
5 | * @date 2016-05-12 14:04:42
6 | *
7 | */
8 |
9 |
--------------------------------------------------------------------------------
/web/webkvmmgr/static/css/tasks.css:
--------------------------------------------------------------------------------
1 | .overview-activities {
2 | width: 35%;
3 | float: right;
4 | }
5 |
6 | .overview-activities .activities-inner {
7 | background: rgb(255,255,255);
8 | padding: 20px;
9 | margin-right: 20px;
10 | margin-bottom: 20px;
11 | }
12 |
13 | .overview-activities .activities-title {
14 | padding: 5px 0;
15 | }
16 | .activities-title {
17 | padding: 5px 20px;
18 | font-weight: 700;
19 | margin: 0;
20 | }
21 | .activities-title a {
22 | font-size: 12px;
23 | font-weight: 400;
24 | padding: 0 10px;
25 | }
26 |
27 | .overview-activities .activities-items {
28 | margin: 10px 0 0 10px;
29 | }
30 |
31 | .activities-items {
32 | border-left: 3px solid #eee;
33 | padding: 0 0 20px 20px;
34 | margin: 20px 15px 10px 30px;
35 | }
36 | .activities-items .job-status {
37 | display: inline-block;
38 | width: 12px;
39 | height: 12px;
40 | border-radius: 3em;
41 | margin-left: -31px;
42 | margin-top: -2px;
43 | float: left;
44 | border: 3px solid #fff;
45 | }
46 | .activities-items .job-status.successful {
47 | background: #57b382;
48 | box-shadow: 0 0 0 1px #57b382;
49 | }
50 |
51 | .activities-items .job-details {
52 | margin: 0 10px 20px 0;
53 | background: #f8f8f8;
54 | padding: 12px;
55 | -webkit-border-radius: 3px;
56 | -moz-border-radius: 3px;
57 | border-radius: 3px;
58 | }
59 |
60 | .activities-items .job-action {
61 | color: #333;
62 | font-size: 14px;
63 | }
64 |
65 | .activities-items .consumed {
66 | font-size: 12px;
67 | color: #777;
68 | vertical-align: top;
69 | background: #f8f8f8;
70 | padding: 2px 6px;
71 | -webkit-border-radius: 3em;
72 | -moz-border-radius: 3em;
73 | border-radius: 3em;
74 | margin-top: -3px;
75 | float: right;
76 | }
77 |
78 | .activities-items .job-time {
79 | display: block;
80 | font-size: 12px;
81 | color: #777;
82 | line-height: 1.8em;
83 | }
84 |
85 | .activities-items .resources {
86 | color: #777;
87 | margin: 10px 0;
88 | line-height: 1.6em;
89 | }
90 |
91 | .activities-items .id {
92 | padding: 0 5px;
93 | border-radius: 2px;
94 | background: #e7f4fb;
95 | margin: 0 5px;
96 | }
97 |
98 | ol, ol li, ul, ul li {
99 | margin: 0;
100 | padding: 0;
101 | list-style-type: none;
102 | }
103 |
104 | /*--------------------------------*/
105 | .page-activities {
106 | width: 80%;
107 | margin: 20px auto;
108 | background: rgb(255,255,255);
109 | padding: 30px 0;
110 | }
111 | h4 {
112 | font-size: 16px;
113 | }
--------------------------------------------------------------------------------
/web/webkvmmgr/static/images/avatar.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/web/webkvmmgr/static/images/bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/web/webkvmmgr/static/images/bg.png
--------------------------------------------------------------------------------
/web/webkvmmgr/static/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/web/webkvmmgr/static/images/favicon.ico
--------------------------------------------------------------------------------
/web/webkvmmgr/static/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/web/webkvmmgr/static/images/logo.png
--------------------------------------------------------------------------------
/web/webkvmmgr/static/images/logofx.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/web/webkvmmgr/static/images/logofx.jpg
--------------------------------------------------------------------------------
/web/webkvmmgr/static/images/logofx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/web/webkvmmgr/static/images/logofx.png
--------------------------------------------------------------------------------
/web/webkvmmgr/static/images/main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/web/webkvmmgr/static/images/main.png
--------------------------------------------------------------------------------
/web/webkvmmgr/static/images/password.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/web/webkvmmgr/static/images/username.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/web/webkvmmgr/static/js/common.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @authors Crazw (craazw@gmail.com)
4 | * @date 2015-05-12 21:00:24
5 | * @version 0.0.1
6 | */
7 |
8 | // text框
9 | var newTextDiv = function(options){
10 | var html = '
';
21 | return $(html);
22 | };
23 |
24 | //hidden隐藏属性
25 | var newHiddenDiv = function(option){
26 | return '
';
27 | };
28 |
29 | //disable的文本属性
30 | var newDisableDiv = function(options){
31 | return '
'
32 | };
33 |
34 | //一个填写框的modal
35 | var basic_modal_temp = function(options){
36 | $("#basicModal").modal();
37 |
38 | // 修改提交地址
39 | $("#basicModal").find(".form-horizontal").attr('action', options.url);
40 |
41 | // 修改标题
42 | $("#basicModal").find(".modal-title").html(options.title);
43 |
44 | // 先清空再添加元素
45 | var body = $("#basicModal").find(".modal-body");
46 | body.empty()
47 |
48 | // 赋值
49 | body.append( newHiddenDiv("sn") );
50 | $('.sn').val(options.sn);
51 | body.append( newHiddenDiv("action") );
52 | $('.action').val(options.field);
53 | body.append( newDisableDiv({label: '设备SN', class_name: 'now-sn'}) )
54 | $('.now-sn').html(options.sn);
55 | body.append( newTextDiv({ require: true, label: options.label, name: 'value', pla: options.pla }) );
56 | };
57 |
58 | //添加虚拟机
59 | $(function(){
60 | $(".create-ins").click(function(){
61 | $("#createIns").modal();
62 | var sn = $(this).parents(".father-opt").find(".sn").html();
63 | $('.now-sn').html(sn);
64 | $('.sn').val(sn);
65 | });
66 | });
67 |
68 | //关闭虚拟机
69 | $(function(){
70 | $(".ins-stop").click(function(){
71 | $("#basicTaskModal").modal();
72 |
73 | // 修改提交地址
74 | $("#basicTaskModal").find(".form-horizontal").attr('action', '/api/instance/');
75 |
76 | // 修改标题
77 | $("#basicTaskModal").find(".modal-title").html('关闭虚拟机');
78 |
79 | // 先清空再添加元素
80 | var body = $("#basicTaskModal").find(".modal-body");
81 | body.empty()
82 |
83 | // 赋值
84 | var sn = $(this).parents(".father-opt").find(".sn").html();
85 | var name = $(this).parents(".father-opt").find(".name").html();
86 | body.append( '
确定执行关闭虚拟机**' + name + '**的操作?
' )
87 | body.append( newHiddenDiv("sn") );
88 | $('.sn').val(sn);
89 | body.append( newHiddenDiv("name") );
90 | $('.name').val(name);
91 | body.append( newHiddenDiv("action") );
92 | $('.action').val("stop");
93 | });
94 | });
95 |
96 | //启动虚拟机
97 | $(function(){
98 | $(".ins-start").click(function(){
99 | $("#basicTaskModal").modal();
100 |
101 | // 修改提交地址
102 | $("#basicTaskModal").find(".form-horizontal").attr('action', '/api/instance/');
103 |
104 | // 修改标题
105 | $("#basicTaskModal").find(".modal-title").html('开启虚拟机');
106 |
107 | // 先清空再添加元素
108 | var body = $("#basicTaskModal").find(".modal-body");
109 | body.empty()
110 |
111 | // 赋值
112 | var sn = $(this).parents(".father-opt").find(".sn").html();
113 | var name = $(this).parents(".father-opt").find(".name").html();
114 | body.append( '
确定执行开启虚拟机**' + name + '**的操作?
' )
115 | body.append( newHiddenDiv("sn") );
116 | $('.sn').val(sn);
117 | body.append( newHiddenDiv("name") );
118 | $('.name').val(name);
119 | body.append( newHiddenDiv("action") );
120 | $('.action').val("start");
121 | });
122 | });
123 |
124 | //虚拟机创建快照
125 | $(function(){
126 | $(".ins-snapshot").click(function(){
127 | $("#basicTaskModal").modal();
128 |
129 | // 修改提交地址
130 | $("#basicTaskModal").find(".form-horizontal").attr('action', '/api/instance/');
131 |
132 | // 修改标题
133 | $("#basicTaskModal").find(".modal-title").html('创建快照');
134 |
135 | // 先清空再添加元素
136 | var body = $("#basicTaskModal").find(".modal-body");
137 | body.empty()
138 |
139 | // 赋值
140 | var sn = $(this).parents(".father-opt").find(".sn").html();
141 | var name = $(this).parents(".father-opt").find(".name").html();
142 | body.append( newHiddenDiv("sn") );
143 | $('.sn').val(sn);
144 | body.append( newDisableDiv({label: '设备SN', class_name: 'now-sn'}) )
145 | $('.now-sn').html(sn);
146 | body.append( newDisableDiv({label: '设备SN', class_name: 'now-name'}) )
147 | $('.now-name').html(name);
148 | body.append( newTextDiv({ require: true, label: '快照名称', name: 'snap_name', pla: '输入快照名称', pattern: '[a-z][\\w]{2,19}$' }) );
149 |
150 | body.append( newHiddenDiv("name") );
151 | $('.name').val(name);
152 | body.append( newHiddenDiv("action") );
153 | $('.action').val("snapshot");
154 | body.append( newHiddenDiv("task_type") );
155 | $('.task_type').val(4);
156 | });
157 | });
158 |
159 | //删除虚拟机
160 | $(function(){
161 | $(".ins-delete").click(function(){
162 | $("#basicTaskModal").modal();
163 |
164 | // 修改提交地址
165 | $("#basicTaskModal").find(".form-horizontal").attr('action', '/api/instance/');
166 |
167 | // 修改标题
168 | $("#basicTaskModal").find(".modal-title").html('删除虚拟机');
169 |
170 | // 先清空再添加元素
171 | var body = $("#basicTaskModal").find(".modal-body");
172 | body.empty()
173 |
174 | // 赋值
175 | var sn = $(this).parents(".father-opt").find(".sn").html();
176 | var name = $(this).parents(".father-opt").find(".name").html();
177 | body.append('
');
178 |
179 | body.append( newHiddenDiv("sn") );
180 | $('.sn').val(sn);
181 | body.append( newHiddenDiv("name") );
182 | $('.name').val(name);
183 | body.append( newHiddenDiv("action") );
184 | $('.action').val("delete");
185 | });
186 | });
--------------------------------------------------------------------------------
/web/webkvmmgr/static/js/instance.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @authors Crazw (craazw@gmail.com)
4 | * @date 2015-05-12 21:00:24
5 | * @version 0.0.1
6 | */
7 |
8 | //等网页加载完毕再执行
9 | window.onload = function () {
10 | $(function(){
11 | $(".recover-snap").click(function(){
12 | $("#basicTaskModal").modal();
13 |
14 | // 修改提交地址
15 | $("#basicTaskModal").find(".form-horizontal").attr('action', '/api/instance/');
16 |
17 | // 修改标题
18 | $("#basicTaskModal").find(".modal-title").html('恢复快照');
19 |
20 | // 先清空再添加元素
21 | var body = $("#basicTaskModal").find(".modal-body");
22 | body.empty()
23 |
24 | // 赋值
25 | var sn = $(this).parents(".father-opt").find(".sn").html();
26 | var name = $(this).parents(".father-opt").find(".name").html();
27 | var snap_name = $(this).parents(".father-opt").find(".snap_name").html();
28 | var snap_mem_size = $(this).parents(".father-opt").find(".snap_mem_size").html();
29 |
30 | body.append( '
确定执行恢复虚拟机**' + name + '**的快照操作?
' )
31 | body.append( newHiddenDiv("sn") );
32 | $('.sn').val(sn);
33 | body.append( newHiddenDiv("name") );
34 | $('.name').val(name);
35 | body.append( newHiddenDiv("snap_name") );
36 | $('.snap_name').val(snap_name);
37 | body.append( newHiddenDiv("snap_mem_size") );
38 | $('.snap_mem_size').val(snap_mem_size);
39 | body.append( newHiddenDiv("action") );
40 | $('.action').val("snapshot");
41 | body.append( newHiddenDiv("task_type") );
42 | $('.task_type').val(5);
43 | });
44 | });
45 | $(function(){
46 | $(".del-snap").click(function(){
47 | $("#basicTaskModal").modal();
48 |
49 | // 修改提交地址
50 | $("#basicTaskModal").find(".form-horizontal").attr('action', '/api/instance/');
51 |
52 | // 修改标题
53 | $("#basicTaskModal").find(".modal-title").html('创建快照');
54 |
55 | // 先清空再添加元素
56 | var body = $("#basicTaskModal").find(".modal-body");
57 | body.empty()
58 |
59 | // 赋值
60 | var sn = $(this).parents(".father-opt").find(".sn").html();
61 | var name = $(this).parents(".father-opt").find(".name").html();
62 | var snap_name = $(this).parents(".father-opt").find(".snap_name").html();
63 |
64 | body.append( '
确定执行恢复虚拟机**' + name + '**的快照操作?
' )
65 | body.append( newHiddenDiv("sn") );
66 | $('.sn').val(sn);
67 | body.append( newHiddenDiv("name") );
68 | $('.name').val(name);
69 | body.append( newHiddenDiv("snap_name") );
70 | $('.snap_name').val(snap_name);
71 | body.append( newHiddenDiv("action") );
72 | $('.action').val("snapshot");
73 | body.append( newHiddenDiv("task_type") );
74 | $('.task_type').val(7);
75 | });
76 | });
77 |
78 | // 添加虚拟机配置
79 | $(function(){
80 | $(".add-setting").click(function(){
81 | $("#addSetting").modal();
82 |
83 | //获得当前版本
84 | var sn = $(this).parents(".father-opt").find(".sn").html();
85 | var name = $(this).parents(".father-opt").find(".name").html();
86 |
87 | // 设置隐藏属性
88 | $('.sn').val(sn);
89 | $('.name').val(name);
90 |
91 | // 设置其他参数
92 | $('.now-sn').html(sn);
93 | $('.now-name').html(name);
94 | });
95 | });
96 |
97 | // 虚拟机网络配置
98 | $(function(){
99 | $(".set-net").click(function(){
100 | $("#setNet").modal();
101 |
102 | //获得当前版本
103 | var sn = $(this).parents(".father-opt").find(".sn").html();
104 | var name = $(this).parents(".father-opt").find(".name").html();
105 |
106 | // 设置隐藏属性
107 | $('.sn').val(sn);
108 | $('.name').val(name);
109 |
110 | // 设置其他参数
111 | $('.now-sn').html(sn);
112 | $('.now-name').html(name);
113 | });
114 | });
115 | }
--------------------------------------------------------------------------------
/web/webkvmmgr/static/js/login.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crazw/webkvmmgr/77cfcad2ed7fa13a0e1f2f8e7c0c61330a76fb50/web/webkvmmgr/static/js/login.js
--------------------------------------------------------------------------------
/web/webkvmmgr/static/js/server.js:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @authors Crazw (craazw@gmail.com)
4 | * @date 2015-05-12 21:00:24
5 | * @version 0.0.1
6 | */
7 |
8 | //等网页加载完毕再执行
9 | window.onload = function () {
10 | //修改设备别名
11 | $(function(){
12 | $(".rename-alias").click(function(){
13 | var sn = $(this).parents(".father-opt").find(".sn").html();
14 | basic_modal_temp({
15 | sn: sn,
16 | url: '/api/server/',
17 | title: '修改设备别名',
18 | field: 'alias',
19 | label: '新的别名',
20 | pla: '清华CDS01'
21 | })
22 | });
23 | });
24 |
25 | //修改设备单位名称
26 | $(function(){
27 | $(".rename-name").click(function(){
28 | var sn = $(this).parents(".father-opt").find(".sn").html();
29 | basic_modal_temp({
30 | sn: sn,
31 | url: '/api/server/',
32 | title: '修改设备单位名称',
33 | field: 'name',
34 | label: '新的单位名称',
35 | pla: '清华大学'
36 | })
37 | });
38 | });
39 |
40 | //设备其他详情
41 | $(function(){
42 | $(".server-main-info").click(function(){
43 | $("#basicModal").modal();
44 |
45 | // 修改提交地址
46 | $("#basicModal").find(".form-horizontal").attr('action', '#');
47 |
48 | // 修改标题
49 | $("#basicModal").find(".modal-title").html('设备详情信息');
50 |
51 | // 先清空再添加元素
52 | var body = $("#basicModal").find(".modal-body");
53 | body.empty()
54 |
55 | // 赋值
56 | var sn = $(this).parents(".father-opt").find(".sn").html();
57 | body.append( newDisableDiv({label: '设备SN', class_name: 'now-sn'}) )
58 | $('.now-sn').html(sn);
59 |
60 | var ip = $(this).parents(".father-opt").find(".ip").html();
61 | body.append( newDisableDiv({label: "出口IP", class_name: 'ip'}) )
62 | $('.ip').html(ip)
63 |
64 | var architecture = $(this).parents(".father-opt").find(".architecture").html();
65 | body.append( newDisableDiv({label: "系统位数", class_name: 'architecture'}) )
66 | $('.architecture').html(architecture)
67 |
68 | var version = $(this).parents(".father-opt").find(".version").html();
69 | body.append( newDisableDiv({label: "业务包版本", class_name: 'version'}) )
70 | $('.version').html(version)
71 |
72 | var libvirt_version = $(this).parents(".father-opt").find(".libvirt_version").html();
73 | body.append( newDisableDiv({label: "libvirt版本", class_name: 'libvirt_version'}) )
74 | $('.libvirt_version').html(libvirt_version)
75 |
76 | var hv_version = $(this).parents(".father-opt").find(".hv_version").html();
77 | body.append( newDisableDiv({label: "hypervisor版本", class_name: 'hv_version'}) )
78 | $('.hv_version').html(hv_version)
79 |
80 | var cpu_name = $(this).parents(".father-opt").find(".cpu_name").html();
81 | body.append( newDisableDiv({label: "CPU名称", class_name: 'cpu_name'}) )
82 | $('.cpu_name').html(cpu_name)
83 |
84 | });
85 | });
86 |
87 | //添加虚拟机
88 | $(function(){
89 | $(".create-ins").click(function(){
90 | $("#createIns").modal();
91 | var sn = $(this).parents(".father-opt").find(".sn").html();
92 | $('.now-sn').html(sn);
93 | $('.sn').val(sn);
94 | });
95 | });
96 |
97 | //添加镜像模板
98 | $(function(){
99 | $(".create-ios-temp").click(function(){
100 | $("#createIosTemp").modal();
101 |
102 | var sn = $(this).parents(".father-opt").find(".sn").html();
103 | $('.now-sn').html(sn);
104 | $('.sn').val(sn);
105 |
106 | });
107 | });
108 |
109 | //添加ISO
110 | $(function(){
111 | $(".add-vmfile").click(function(){
112 | $("#addVmFile").modal();
113 |
114 | //获得当前版本
115 | var sn = $(this).parents(".father-opt").find(".sn").html();
116 | // 设置隐藏属性
117 | $('.sn').val(sn);
118 |
119 | // 设置其他参数
120 | $('.now-sn').html(_now_sn);
121 | });
122 | });
123 |
124 | //删除镜像模板
125 | $(function(){
126 | $(".iostemp-delete").click(function(){
127 | $("#basicModal").modal();
128 |
129 | // 修改提交地址
130 | $("#basicModal").find(".form-horizontal").attr('action', '/api/iostemp/');
131 |
132 | // 修改标题
133 | $("#basicModal").find(".modal-title").html('删除镜像模板');
134 |
135 | // 先清空再添加元素
136 | var body = $("#basicModal").find(".modal-body");
137 | body.empty()
138 |
139 | // 赋值
140 | var id = $(this).parents(".father-opt").find(".id").html();
141 | body.append( newHiddenDiv("id") );
142 | $('.id').val(id);
143 |
144 | body.append( newHiddenDiv("action") );
145 | $('.action').val("delete");
146 |
147 | var sn = $(this).parents(".father-opt").find(".sn").html();
148 | body.append( newHiddenDiv("sn") );
149 | $('.sn').val(sn);
150 | body.append( newDisableDiv({label: '设备SN', class_name: 'now-sn'}) )
151 | $('.now-sn').html(sn);
152 |
153 | var name = $(this).parents(".father-opt").find(".name").html();
154 | body.append( newDisableDiv({label: "镜像模板名称", class_name: 'name'}) )
155 | $('.name').html(name)
156 |
157 | });
158 | });
159 | }
--------------------------------------------------------------------------------
/web/webkvmmgr/urls.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 | """webkvmmgr URL Configuration
3 |
4 | The `urlpatterns` list routes URLs to views. For more information please see:
5 | https://docs.djangoproject.com/en/1.9/topics/http/urls/
6 | Examples:
7 | Function views
8 | 1. Add an import: from my_app import views
9 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
10 | Class-based views
11 | 1. Add an import: from other_app.views import Home
12 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
13 | Including another URL conf
14 | 1. Import the include() function: from django.conf.urls import url, include
15 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
16 | """
17 | from django.conf.urls import url
18 | from django.contrib import admin
19 | from server import views as servers_views
20 | from instance import views as instances_views
21 | from api import views as api_views
22 |
23 | urlpatterns = [
24 | url(r'^admin/', admin.site.urls),
25 | url(r'^$', api_views.login_view, name='index'),
26 |
27 | # 宿主机相关
28 | url(r'^server/list$', servers_views.server_list, name='server_list'),
29 | url(r'^server/(CAS\d{10})/(\w+)/$', servers_views.server_info),
30 |
31 | # 虚拟机相关
32 | url(r'^instance/(CAS\d{10})/(\w+)/(\w+)/$', instances_views.instance_info, name='instance'),
33 |
34 | # 接口相关
35 | url(r'^accounts/login/$', api_views.login_view, name='login'),
36 | url(r'^accounts/logout/$', api_views.logout_view, name='logout'),
37 |
38 | # 宿主机接口相关
39 | url(r'^api/server/$', api_views.server_api, name='server_api'),
40 | url(r'^api/instance/$', api_views.instance_api, name='instance_api'),
41 | url(r'^api/iostemp/$', api_views.iostemp_api, name='iostemp_api'),
42 | url(r'^api/vmfile/$', api_views.vmfile_api, name='vmfile_api'),
43 | ]
44 |
--------------------------------------------------------------------------------
/web/webkvmmgr/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for webkvmmgr 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/1.9/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", "webkvmmgr.settings")
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------