Commit caa59fbd authored by lizeen's avatar lizeen
Browse files

add websocket and pod

parent af81a220
Showing with 118 additions and 586 deletions
+118 -586
......@@ -18,4 +18,4 @@ node_modules
*.sln
*.sw?
logs/
.history/
.history
from api import SlashOptionRouter
from api.views import user, cluster, pod
from api.views import user, cluster, pod, namespace
router = SlashOptionRouter()
router.register('user', user.UserViewSet, basename='user')
router.register('cluster', cluster.ClusterViewSet, basename='cluster')
router.register('pods/(?P<cluster>[^/.]+)', pod.PodViewSet, basename='pod')
router.register('namespace/(?P<cluster>[^/.]+)', namespace.NamespaceViewSet, basename='namespace')
urlpatterns = router.urls
import logging
from time import sleep
from django.http import HttpResponse
from rest_framework import viewsets
......@@ -27,12 +28,14 @@ class ClusterViewSet(viewsets.GenericViewSet):
@api_decorator('List cluster')
def list(self, _):
sleep(3)
clusters = Cluster.filter()
data = []
for cluster in clusters:
data.append({
'name': cluster.name,
'token': cluster.token,
'status': '正常',
'create_time': cluster.create_time,
'update_time': cluster.update_time
})
......
import logging
from rest_framework import viewsets
from api.views import api_decorator
from service.kuberesource.namespace import NamespaceResource
from utils import CommonReturn, Code
from . import serializers
logger = logging.getLogger(__name__)
class NamespaceViewSet(viewsets.GenericViewSet):
@api_decorator('Create namespace')
def create(self, req):
return CommonReturn(Code.SUCCESS, 'success')
@api_decorator('List namespace', serializer_class=serializers.GeneralSerializer)
def list(self, req):
params = req.get('params')
req_params = {
'name': params.get('name'),
}
ns_resource = NamespaceResource(req.get('cluster'))
res = ns_resource.list(req_params)
return res
......@@ -26,7 +26,7 @@ class Auth:
if user.password != encrypted_pwd:
return CommonReturn(Code.AUTH_ERROR, '密码不正确,请重新输入!')
token = uuid.uuid4().hex
Token(token=token, username=username).save(expire=1800, add_sets=False)
Token(token=token, username=username).save(expire=43200, add_sets=False)
user.last_login = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
user.save(add_sets=False)
return CommonReturn(Code.SUCCESS, data={'token': token})
......
import logging
from service.kuberesource import KubeResource
logger = logging.getLogger(__name__)
class NamespaceResource(KubeResource):
RESOURCE_TYPE = 'namespace'
import logging
from service.kuberesource import KubeResource
from utils import CommonReturn, Code
logger = logging.getLogger(__name__)
class WatchResource(KubeResource):
RESOURCE_TYPE = 'watch'
def close_watch(self):
has_watch_client = self.middle_message.has_watch_client(self.cluster)
if not has_watch_client:
return self.get({'action': 'close'})
return CommonReturn(Code.SUCCESS, "Success")
def open_watch(self):
return self.get({"action": "open"})
......@@ -52,6 +52,29 @@ class MiddleMessage:
except Exception as exc:
logger.error('websocket handle subscribe data error: %s' % exc, exc_info=True)
@classmethod
def cluster_watch_queue_key(cls, cluster):
return 'osp:cluster_watch:%s' % cluster
def get_watch(self, cluster):
watch_queue_key = self.cluster_watch_queue_key(cluster)
self.pubsub.subscribe(watch_queue_key)
for data in self.pubsub.listen():
try:
logger.info('receive watch data: %s' % data)
d = data.get('data')
if d == 1:
continue
try:
data = json.loads(d)
except Exception as exc:
logger.error('subscribe data json error: %s' % exc, exc_info=True)
continue
# watch_response = MiddleResponse.unserialize(data)
yield data
except Exception as exc:
logger.error('websocket handle subscribe data error: %s' % exc, exc_info=True)
def send_response(self, middle_response):
request_id = middle_response.request_id
response_data = middle_response.serialize_data()
......@@ -59,6 +82,27 @@ class MiddleMessage:
pipeline.lpush(request_id, response_data).expire(request_id, time=10)
pipeline.execute()
def has_watch_client(self, cluster):
watch_queue_key = self.cluster_watch_queue_key(cluster)
subscribes = self.connection.pubsub_numsub(watch_queue_key)
logger.info('token %s current subscribes: %s' % (watch_queue_key, subscribes))
for s in subscribes:
if s[0].decode('utf-8') == watch_queue_key and s[1] > 0:
return True
return False
def send_watch(self, cluster, middle_response):
watch_queue_key = self.cluster_watch_queue_key(cluster)
subscribes = self.connection.pubsub_numsub(watch_queue_key)
logger.info('token %s current subscribes: %s' % (watch_queue_key, subscribes))
has_sub = False
for s in subscribes:
if s[0].decode('utf-8') == watch_queue_key and s[1] > 0:
has_sub = True
break
if has_sub:
self.connection.publish(watch_queue_key, middle_response.serialize_data())
def send_request(self, middle_request):
request_queue_key = self.cluster_request_queue_key(middle_request.cluster)
subscribes = self.connection.pubsub_numsub(request_queue_key)
......@@ -114,8 +158,9 @@ class MiddleRequest:
class MiddleResponse:
def __init__(self, request_id=None, data=None):
def __init__(self, request_id=None, data=None, res_type=None):
self.request_id = request_id
self.res_type = res_type
self.data = data
def serialize_data(self):
......@@ -124,4 +169,11 @@ class MiddleResponse:
@classmethod
def unserialize(cls, data):
return cls(request_id=data.get('request_id'),
res_type=data.get('res_type'),
data=data.get('data'))
def is_request(self):
return self.res_type == 'request'
def is_watch(self):
return self.res_type == 'watch'
......@@ -19,3 +19,4 @@ pnpm-debug.log*
*.njsproj
*.sln
*.sw?
.history
<template>
<div>
<div id="myChart" style="width: 400px; height: 300px;"></div>
</div>
</template>
<script>
import Highcharts from 'highcharts';
import HighchartsMore from 'highcharts/highcharts-more';
import SolidGauge from 'highcharts/modules/solid-gauge.js'
HighchartsMore(Highcharts)
SolidGauge(Highcharts);
if (!Highcharts.theme) {
Highcharts.setOptions({
chart: {
backgroundColor: 'white'
},
colors: ['#F62366', '#9DFF02', '#0CCDD6'],
title: {
style: {
color: 'silver'
}
},
tooltip: {
style: {
color: 'silver'
}
}
});
}
export default {
mounted() {
this.init();
},
data() {
return {
}
},
methods: {
init() {
this.draw();
},
draw() {
new Highcharts.chart('myChart', {
chart: {
type: 'solidgauge',
marginTop: 50
},
credits: { enabled: false },
title: {
text: 'CPU',
style: {
fontSize: '24px'
}
},
tooltip: {
borderWidth: 0,
backgroundColor: 'none',
shadow: false,
style: {
fontSize: '15px'
},
pointFormat: '{series.name}<br><span style="font-size:1em; color: {point.color}; font-weight: bold">{point.y}%</span>',
positioner: function (labelWidth) {
return {
x: 200 - labelWidth / 2,
y: 140
};
}
},
pane: {
startAngle: 0,
endAngle: 360,
background: [{ // Track for Move
outerRadius: '112%',
innerRadius: '88%',
backgroundColor: 'red',
//Highcharts.Color(Highcharts.getOptions().colors[1]).setOpacity(0.3).get(),
borderWidth: 0
}, { // Track for Exercise
outerRadius: '87%',
innerRadius: '63%',
backgroundColor: Highcharts.Color(Highcharts.getOptions().colors[1]).setOpacity(0.3).get(),
borderWidth: 0
}, { // Track for Stand
outerRadius: '62%',
innerRadius: '38%',
backgroundColor: Highcharts.Color(Highcharts.getOptions().colors[2]).setOpacity(0.3).get(),
borderWidth: 0
}]
},
yAxis: {
min: 0,
max: 100,
lineWidth: 0,
tickPositions: []
},
plotOptions: {
solidgauge: {
borderWidth: '28px', //覆盖层 宽度
dataLabels: {
enabled: false
},
linecap: 'round',
stickyTracking: false
}
},
series: [{
name: 'Move',
// borderColor: Highcharts.getOptions().colors[1],
borderColor: 'yellow',
data: [{
color: Highcharts.getOptions().colors[0],
// color:'yellow',
radius: '100%',
innerRadius: '100%',
y: 80
}]
}, {
name: 'Exercise',
borderColor: Highcharts.getOptions().colors[1],
data: [{
color: Highcharts.getOptions().colors[1],
radius: '75%',
innerRadius: '75%',
y: 65
}]
}, {
name: 'Stand',
borderColor: Highcharts.getOptions().colors[2],
data: [{
color: Highcharts.getOptions().colors[2],
radius: '50%',
innerRadius: '50%',
y: 50
}]
}]
});
}
}
}
</script>
<style lang="stylus">
</style>
\ No newline at end of file
<template>
<div>
<div id="cpu" style="width: 400px; height: 300px;"></div>
</div>
</template>
<script>
import Highcharts from 'highcharts';
import HighchartsMore from 'highcharts/highcharts-more';
import SolidGauge from 'highcharts/modules/solid-gauge.js'
HighchartsMore(Highcharts)
SolidGauge(Highcharts);
if (!Highcharts.theme) {
Highcharts.setOptions({
chart: {
backgroundColor: 'white'
},
colors: ['#F62366', '#9DFF02', '#0CCDD6'],
title: {
style: {
color: 'silver'
}
},
tooltip: {
style: {
color: 'silver'
}
}
});
}
export default {
mounted() {
this.init();
},
data() {
return {
}
},
methods: {
init() {
this.draw();
},
draw() {
new Highcharts.chart('cpu', {
chart: {
type: 'solidgauge',
marginTop: 50
},
credits: { enabled: false },
title: {
text: 'CPU',
style: {
fontSize: '24px'
}
},
tooltip: {
borderWidth: 0,
backgroundColor: 'none',
shadow: false,
style: {
fontSize: '15px'
},
pointFormat: '{series.name}<br><span style="font-size:1em; color: {point.color}; font-weight: bold">{point.y}%</span>',
positioner: function (labelWidth) {
return {
x: 200 - labelWidth / 2,
y: 140
};
}
},
pane: {
startAngle: 0,
endAngle: 360,
background: [{ // Track for Move
outerRadius: '112%',
innerRadius: '88%',
backgroundColor: 'red',
//Highcharts.Color(Highcharts.getOptions().colors[1]).setOpacity(0.3).get(),
borderWidth: 0
}, { // Track for Exercise
outerRadius: '87%',
innerRadius: '63%',
backgroundColor: Highcharts.Color(Highcharts.getOptions().colors[1]).setOpacity(0.3).get(),
borderWidth: 0
}, { // Track for Stand
outerRadius: '62%',
innerRadius: '38%',
backgroundColor: Highcharts.Color(Highcharts.getOptions().colors[2]).setOpacity(0.3).get(),
borderWidth: 0
}]
},
yAxis: {
min: 0,
max: 100,
lineWidth: 0,
tickPositions: []
},
plotOptions: {
solidgauge: {
borderWidth: '28px', //覆盖层 宽度
dataLabels: {
enabled: false
},
linecap: 'round',
stickyTracking: false
}
},
series: [{
name: 'Move',
// borderColor: Highcharts.getOptions().colors[1],
borderColor: 'yellow',
data: [{
color: Highcharts.getOptions().colors[0],
// color:'yellow',
radius: '100%',
innerRadius: '100%',
y: 80
}]
}, {
name: 'Exercise',
borderColor: Highcharts.getOptions().colors[1],
data: [{
color: Highcharts.getOptions().colors[1],
radius: '75%',
innerRadius: '75%',
y: 65
}]
}, {
name: 'Stand',
borderColor: Highcharts.getOptions().colors[2],
data: [{
color: Highcharts.getOptions().colors[2],
radius: '50%',
innerRadius: '50%',
y: 50
}]
}]
});
}
}
}
</script>
<style lang="stylus">
</style>
\ No newline at end of file
export { default as CPU } from './cpu'
export { default as MEM } from './mem'
export { default as POD } from './pod'
\ No newline at end of file
export { default as SolidGauge } from './SolidGauge'
\ No newline at end of file
export { default as SolidGauge } from './solidgauge'
\ No newline at end of file
export { default as SolidGauge } from './solidgauge'
export { default as Line } from './line'
\ No newline at end of file
export { default as SolidGauge } from './solidgauge'
export { default as Ployline } from './line'
\ No newline at end of file
<template>
<div>
<div :id=id style="width: 400px; height: 300px;"></div>
</div>
</template>
<script>
export default {
mounted() {
this.init();
},
data() {
return {}
},
props: {
id: {
type: String,
default: "charts"
},
data: {
type: Object,
default: function () {
return {
backgroundNum: 0,
series: []
}
}
}
},
methods: {
init() {
this.draw();
},
draw() {
new Highcharts.chart(this.id, {
title: {
text: '2010 ~ 2016 年太阳能行业就业人员发展情况'
},
subtitle: {
text: '数据来源:thesolarfoundation.com'
},
yAxis: {
title: {
text: '就业人数'
}
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle'
},
plotOptions: {
series: {
label: {
connectorAllowed: false
},
pointStart: 2010
}
},
series: [{
name: '安装,实施人员',
data: [43934, 52503, 57177, 69658, 97031, 119931, 137133, 154175]
}, {
name: '工人',
data: [24916, 24064, 29742, 29851, 32490, 30282, 38121, 40434]
}, {
name: '销售',
data: [11744, 17722, 16005, 19771, 20185, 24377, 32147, 39387]
}, {
name: '项目开发',
data: [null, null, 7988, 12169, 15112, 22452, 34400, 34227]
}, {
name: '其他',
data: [12908, 5948, 8105, 11248, 8989, 11816, 18274, 18111]
}],
responsive: {
rules: [{
condition: {
maxWidth: 500
},
chartOptions: {
legend: {
layout: 'horizontal',
align: 'center',
verticalAlign: 'bottom'
}
}
}]
}
});
}
}
}
</script>
\ No newline at end of file
<template>
<div>
<div :id=id style="width: 400px; height: 300px;"></div>
</div>
</template>
<script>
import Highcharts from 'highcharts';
export default {
mounted() {
this.init();
},
data() {
return {}
},
props: {
id: {
type: String,
default: "charts"
},
data: {
type: Object,
default: function () {
return {
backgroundNum: 0,
series: []
}
}
}
},
methods: {
init() {
this.draw();
},
draw() {
new Highcharts.chart(this.id, {
title: {
text: '2010 ~ 2016 年太阳能行业就业人员发展情况'
},
subtitle: {
text: '数据来源:thesolarfoundation.com'
},
yAxis: {
title: {
text: '就业人数'
}
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle'
},
plotOptions: {
series: {
label: {
connectorAllowed: false
},
pointStart: 2010
}
},
series: [{
name: '安装,实施人员',
data: [43934, 52503, 57177, 69658, 97031, 119931, 137133, 154175]
}, {
name: '工人',
data: [24916, 24064, 29742, 29851, 32490, 30282, 38121, 40434]
}, {
name: '销售',
data: [11744, 17722, 16005, 19771, 20185, 24377, 32147, 39387]
}, {
name: '项目开发',
data: [null, null, 7988, 12169, 15112, 22452, 34400, 34227]
}, {
name: '其他',
data: [12908, 5948, 8105, 11248, 8989, 11816, 18274, 18111]
}],
responsive: {
rules: [{
condition: {
maxWidth: 500
},
chartOptions: {
legend: {
layout: 'horizontal',
align: 'center',
verticalAlign: 'bottom'
}
}
}]
}
});
}
}
}
</script>
\ No newline at end of file
<template>
<div>
<div :id=id style="width: 400px; height: 300px;"></div>
</div>
</template>
<script>
import Highcharts from 'highcharts';
export default {
mounted() {
this.init();
},
data() {
return {}
},
props: {
id: {
type: String,
default: "charts"
}
},
methods: {
init() {
this.draw();
},
draw() {
new Highcharts.chart(this.id, {
title: {
text: '2010 ~ 2016 年太阳能行业就业人员发展情况'
},
subtitle: {
text: '数据来源:thesolarfoundation.com'
},
yAxis: {
title: {
text: '就业人数'
}
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle'
},
plotOptions: {
series: {
label: {
connectorAllowed: false
},
pointStart: 2010
}
},
series: [{
name: '安装,实施人员',
data: [43934, 52503, 57177, 69658, 97031, 119931, 137133, 154175]
}, {
name: '工人',
data: [24916, 24064, 29742, 29851, 32490, 30282, 38121, 40434]
}, {
name: '销售',
data: [11744, 17722, 16005, 19771, 20185, 24377, 32147, 39387]
}, {
name: '项目开发',
data: [null, null, 7988, 12169, 15112, 22452, 34400, 34227]
}, {
name: '其他',
data: [12908, 5948, 8105, 11248, 8989, 11816, 18274, 18111]
}],
responsive: {
rules: [{
condition: {
maxWidth: 500
},
chartOptions: {
legend: {
layout: 'horizontal',
align: 'center',
verticalAlign: 'bottom'
}
}
}]
}
});
}
}
}
</script>
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment