From eeb45f4c5ebfe2492cb956083f26ee0813fd431d Mon Sep 17 00:00:00 2001 From: BennieMeng Date: Mon, 10 Dec 2018 11:28:08 +0800 Subject: [PATCH 01/22] frontend: select js format --- .../app/shared/select/select.component.html | 9 +++---- .../src/app/shared/select/select.component.ts | 27 +++++++++++-------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/frontend/src/app/shared/select/select.component.html b/src/frontend/src/app/shared/select/select.component.html index 662237930..1a88480f2 100644 --- a/src/frontend/src/app/shared/select/select.component.html +++ b/src/frontend/src/app/shared/select/select.component.html @@ -1,6 +1,5 @@ - + @@ -9,5 +8,5 @@
- + [style.height.px]="barHeight"> + \ No newline at end of file diff --git a/src/frontend/src/app/shared/select/select.component.ts b/src/frontend/src/app/shared/select/select.component.ts index ef88a7bac..54fd4a893 100644 --- a/src/frontend/src/app/shared/select/select.component.ts +++ b/src/frontend/src/app/shared/select/select.component.ts @@ -47,11 +47,9 @@ import { ScrollBarService } from '../client/v1/scrollBar.service'; export class SelectComponent implements AfterViewInit, ControlValueAccessor { _value: any = ''; - barState: string = 'hide'; - showBox: boolean = false; - updateEmit = (_: any) => { - }; - top: number = 0; + barState = 'hide'; + showBox = false; + top = 0; barHeight: number; maxTrans: number; wrap: HTMLElement; @@ -68,6 +66,7 @@ export class SelectComponent implements AfterViewInit, ControlValueAccessor { @Input('type') type = ''; @Input('placeholder') placeholder = ''; @Output() change = new EventEmitter(); + updateEmit = (_: any) => {}; get value() { return this._value; @@ -76,8 +75,10 @@ export class SelectComponent implements AfterViewInit, ControlValueAccessor { set value(value: any) { if (this._value !== value) { if (this.type === 'page') { - this._value = parseInt(value) || null; - if (this._value) this.updateValue(this._value); + this._value = parseInt(value, 10) || null; + if (this._value) { + this.updateValue(this._value); + } } else { this._value = value; this.updateValue(this._value); @@ -114,7 +115,9 @@ export class SelectComponent implements AfterViewInit, ControlValueAccessor { isClickBox(target: Element): boolean { while (target.tagName.toLowerCase() !== 'body') { - if (target.tagName.toLowerCase() === 'wayne-select') return true; + if (target.tagName.toLowerCase() === 'wayne-select') { + return true; + } target = target.parentElement; } return false; @@ -177,7 +180,7 @@ export class SelectComponent implements AfterViewInit, ControlValueAccessor { } docuMouseDown(event) { - let target = event.target; + const target = event.target; if (this.showBox) { if (!this.isClickBox(target)) { this.destoryBar(); @@ -203,7 +206,9 @@ export class SelectComponent implements AfterViewInit, ControlValueAccessor { */ scrollEvent(event) { event.stopPropagation(); - if (Object.prototype.toString.call(this.clickStart) !== '[object Null]') return; + if (Object.prototype.toString.call(this.clickStart) !== '[object Null]') { + return; + } const target = event.target; this.top = Number((target.scrollTop / target.clientHeight * 100).toFixed(2)); } @@ -226,7 +231,7 @@ export class SelectComponent implements AfterViewInit, ControlValueAccessor { } this.removeStyle(this._options); this._options.forEach(option => { - if (option.value == this.value) { + if (option.value === this.value) { option.el.nativeElement.style.background = 'rgba(232, 237, 246, .45)'; this.wrap.scrollTop = option.el.nativeElement.offsetTop - 5; } From 6882bafdc4981465962d605266694ad5bb5343ce Mon Sep 17 00:00:00 2001 From: chengyumeng <792400644@qq.com> Date: Tue, 11 Dec 2018 11:39:14 +0800 Subject: [PATCH 02/22] backend:add develop tools for webhook --- Makefile | 3 +++ docker-compose.yaml | 2 ++ hack/dev/webhook/echo.py | 21 +++++++++++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 hack/dev/webhook/echo.py diff --git a/Makefile b/Makefile index f068fc05d..f59c97192 100644 --- a/Makefile +++ b/Makefile @@ -22,6 +22,9 @@ run-backend: run-worker: cd src/backend/ && bee run -main=./main.go -runargs="worker -t AuditWorker -c 2" +run-webhook: + cd src/backend/ && bee run -main=./main.go -runargs="worker -t WebhookWorker -c 2" + run-frontend: cd src/frontend/ && npm start diff --git a/docker-compose.yaml b/docker-compose.yaml index 7c2727336..47abd27aa 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -3,6 +3,8 @@ services: rabbitmq: environment: RABBITMQ_NODENAME: "rabbit" + RABBITMQ_DEFAULT_USER: "guest" + RABBITMQ_DEFAULT_PASS: "guest" image: rabbitmq:3.7.8-management networks: - default diff --git a/hack/dev/webhook/echo.py b/hack/dev/webhook/echo.py new file mode 100644 index 000000000..2b9bab8f4 --- /dev/null +++ b/hack/dev/webhook/echo.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python + +import SimpleHTTPServer +import SocketServer + +PORT = 8000 + +class GetHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): + def do_GET(self): + print(self.headers) + self.send_response(200, "") + def do_POST(self): + print(self.headers) + content_length = self.headers.getheaders('content-length') + length = int(content_length[0]) if content_length else 0 + print(self.rfile.read(length)) + self.send_response(200, "") + +Handler = GetHandler +httpd = SocketServer.TCPServer(("", PORT), Handler) +httpd.serve_forever() \ No newline at end of file From 68f82cad09edf02553aa018c1b66d1b3671ba047 Mon Sep 17 00:00:00 2001 From: chengyumeng <792400644@qq.com> Date: Tue, 11 Dec 2018 12:15:45 +0800 Subject: [PATCH 03/22] backend:add namespace user action webhook --- .../controllers/permission/namespace_user.go | 13 +++++++++++-- src/backend/models/namespace_user.go | 5 ++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/backend/controllers/permission/namespace_user.go b/src/backend/controllers/permission/namespace_user.go index 9c79d3cd6..0a721537a 100644 --- a/src/backend/controllers/permission/namespace_user.go +++ b/src/backend/controllers/permission/namespace_user.go @@ -6,6 +6,7 @@ import ( "github.com/Qihoo360/wayne/src/backend/controllers/base" "github.com/Qihoo360/wayne/src/backend/models" "github.com/Qihoo360/wayne/src/backend/util/logs" + "github.com/Qihoo360/wayne/src/backend/workers/webhook" "github.com/mitchellh/mapstructure" ) @@ -118,6 +119,7 @@ func (c *NamespaceUserController) Create() { c.HandleError(err) return } + webhook.PublishEventMember(c.NamespaceId, c.AppId, c.User.Name, c.Ctx.Input.IP(), webhook.AddMember, *namespaceUser.User) c.Success(namespaceUser) } @@ -173,6 +175,7 @@ func (c *NamespaceUserController) Update() { c.HandleError(err) return } + webhook.PublishEventMember(c.NamespaceId, c.AppId, c.User.Name, c.Ctx.Input.IP(), webhook.UpdateMember, *namespaceUser.User) c.Success(namespaceUser) } @@ -190,13 +193,19 @@ func (c *NamespaceUserController) Delete() { if oneGroup != "" { groupsFlag = false } - - err := models.NamespaceUserModel.DeleteById(int64(id), groupsFlag) + namespaceUser, err := models.NamespaceUserModel.GetById(int64(id), groupsFlag) + if err != nil { + logs.Error("get by %d error.%v", id, err) + c.HandleError(err) + return + } + err = models.NamespaceUserModel.DeleteById(int64(id), groupsFlag) if err != nil { logs.Error("delete %d error.%v", id, err) c.HandleError(err) return } + webhook.PublishEventMember(c.NamespaceId, c.AppId, c.User.Name, c.Ctx.Input.IP(), webhook.DeleteMember, *namespaceUser.User) c.Success(nil) } diff --git a/src/backend/models/namespace_user.go b/src/backend/models/namespace_user.go index 4fe9c7aef..3cc12a55a 100644 --- a/src/backend/models/namespace_user.go +++ b/src/backend/models/namespace_user.go @@ -119,7 +119,10 @@ func (n *namespaceUserModel) GetById(id int64, allGroupFlag bool) (v *NamespaceU if err = Ormer().Read(v); err != nil { return nil, err } - + v.User, err = UserModel.GetUserById(v.User.Id) + if err != nil { + return nil, err + } if allGroupFlag { namespaceUsers := []NamespaceUser{} _, err := Ormer().QueryTable(TableNameNamespaceUser).Filter("Namespace", v.Namespace.Id).Filter("User", v.User.Id).RelatedSel("Group").All(&namespaceUsers) From 5be82460eff88248d6fe821de1e47bfa6a7f16ef Mon Sep 17 00:00:00 2001 From: chengyumeng <792400644@qq.com> Date: Tue, 11 Dec 2018 14:34:46 +0800 Subject: [PATCH 04/22] backend:add ingress webhook --- .../controllers/kubernetes/ingress/ingress.go | 17 ++++++++- src/backend/models/hookevent/event.go | 9 ++++- src/backend/workers/webhook/payload.go | 36 +++++++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/src/backend/controllers/kubernetes/ingress/ingress.go b/src/backend/controllers/kubernetes/ingress/ingress.go index a4748f58d..48f123b9e 100644 --- a/src/backend/controllers/kubernetes/ingress/ingress.go +++ b/src/backend/controllers/kubernetes/ingress/ingress.go @@ -6,8 +6,10 @@ import ( "github.com/Qihoo360/wayne/src/backend/client" "github.com/Qihoo360/wayne/src/backend/controllers/base" "github.com/Qihoo360/wayne/src/backend/models" + "github.com/Qihoo360/wayne/src/backend/models/response" "github.com/Qihoo360/wayne/src/backend/resources/ingress" "github.com/Qihoo360/wayne/src/backend/util/logs" + "github.com/Qihoo360/wayne/src/backend/workers/webhook" kapiv1beta1 "k8s.io/api/extensions/v1beta1" ) @@ -88,6 +90,15 @@ func (c *KubeIngressController) Deploy() { c.HandleError(err) return } + webhook.PublishEventIngress(c.NamespaceId, c.AppId, c.User.Name, c.Ctx.Input.IP(), webhook.OnlineIngress, response.Resource{ + Type: publishHistory.Type, + ResourceId: publishHistory.ResourceId, + ResourceName: publishHistory.ResourceName, + TemplateId: publishHistory.TemplateId, + Cluster: publishHistory.Cluster, + Status: publishHistory.Status, + Message: publishHistory.Message, + }) c.Success("ok") } @@ -123,6 +134,10 @@ func (c *KubeIngressController) Offline() { c.HandleError(err) return } + webhook.PublishEventIngress(c.NamespaceId, c.AppId, c.User.Name, c.Ctx.Input.IP(), webhook.OfflineIngress, response.Resource{ + Type: models.PublishTypeIngress, + ResourceName: name, + Cluster: cluster, + }) c.Success("OK") - return } diff --git a/src/backend/models/hookevent/event.go b/src/backend/models/hookevent/event.go index 311ddf7a8..e417b1c66 100644 --- a/src/backend/models/hookevent/event.go +++ b/src/backend/models/hookevent/event.go @@ -18,7 +18,13 @@ var ( EventService = &HookEvent{ Key: "service", Name: "负载均衡", - Description: "负载均衡相关动作行为,如创建、上下线等", + Description: "负载均衡相关动作行为,如上下线等", + } + + EventIngress = &HookEvent{ + Key: "ingress", + Name: "Ingress", + Description: "Ingress 相关动作行为,如上下线等", } EventMember = &HookEvent{ @@ -36,4 +42,5 @@ func init() { Registry(EventDeployment) Registry(EventService) Registry(EventMember) + Registry(EventIngress) } diff --git a/src/backend/workers/webhook/payload.go b/src/backend/workers/webhook/payload.go index 3a2f57e3c..016861866 100644 --- a/src/backend/workers/webhook/payload.go +++ b/src/backend/workers/webhook/payload.go @@ -33,6 +33,11 @@ type EventServicePayload struct { Service response.Resource `json:"service"` } +type EventIngressPayload struct { + Action Action `json:"action"` + Ingress response.Resource `json:"ingress"` +} + type EventMemberPayload struct { Action Action `json:"action"` Member response.User `json:"member"` @@ -48,6 +53,8 @@ const ( DeleteDeployment Action = "OfflineDeployment" OnlineService Action = "OnlineService" OfflineService Action = "OfflineService" + OnlineIngress Action = "OnlineIngress" + OfflineIngress Action = "OfflineIngress" ) func PublishEventDeployment(namespaceId int64, appId int64, user string, ip string, action Action, deployment response.Resource) { @@ -108,6 +115,35 @@ func PublishEventService(namespaceId int64, appId int64, user string, ip string, } } +func PublishEventIngress(namespaceId int64, appId int64, user string, ip string, action Action, ingress response.Resource) { + if !enable() { + return + } + messageData, err := json.Marshal(message.HookMessageData{ + NamespaceId: namespaceId, + AppId: appId, + User: user, + IP: ip, + Datetime: time.Now(), + EventKey: hookevent.EventIngress.Key, + Payload: EventIngressPayload{ + Action: action, + Ingress: ingress, + }, + }) + if err != nil { + logs.Error(err) + } else { + msg := message.Message{ + Type: message.TypeHook, + Data: json.RawMessage(messageData), + } + if err := bus.Notify(msg); err != nil { + logs.Error(err) + } + } +} + func PublishEventMember(namespaceId int64, appId int64, user string, ip string, action Action, member models.User) { if !enable() { return From abf841000a672a80da8dcfe1ddc066c62a4a49c3 Mon Sep 17 00:00:00 2001 From: chengyumeng <792400644@qq.com> Date: Tue, 11 Dec 2018 14:53:55 +0800 Subject: [PATCH 05/22] backend:when use webhook,pass kubernetes object message --- .../controllers/kubernetes/deployment/deployment.go | 1 + src/backend/controllers/kubernetes/ingress/ingress.go | 7 ++++--- src/backend/models/response/response.go | 1 + src/backend/resources/ingress/ingress.go | 6 +++--- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/backend/controllers/kubernetes/deployment/deployment.go b/src/backend/controllers/kubernetes/deployment/deployment.go index 88821fda3..c1c1a61c2 100644 --- a/src/backend/controllers/kubernetes/deployment/deployment.go +++ b/src/backend/controllers/kubernetes/deployment/deployment.go @@ -175,6 +175,7 @@ func (c *KubeDeploymentController) Deploy() { Cluster: publishHistory.Cluster, Status: publishHistory.Status, Message: publishHistory.Message, + Object: kubeDeployment, }) c.Success("ok") } else { diff --git a/src/backend/controllers/kubernetes/ingress/ingress.go b/src/backend/controllers/kubernetes/ingress/ingress.go index 48f123b9e..713767143 100644 --- a/src/backend/controllers/kubernetes/ingress/ingress.go +++ b/src/backend/controllers/kubernetes/ingress/ingress.go @@ -69,7 +69,7 @@ func (c *KubeIngressController) Deploy() { logs.Critical("insert log into database failed: %s", err) } }() - _, err = ingress.CreateOrUpdateService(k8sClient, &kubeIngress) + _, err = ingress.CreateOrUpdate(k8sClient, &kubeIngress) if err != nil { publishHistory.Status = models.ReleaseFailure publishHistory.Message = err.Error() @@ -98,6 +98,7 @@ func (c *KubeIngressController) Deploy() { Cluster: publishHistory.Cluster, Status: publishHistory.Status, Message: publishHistory.Message, + Object: kubeIngress, }) c.Success("ok") } @@ -111,7 +112,7 @@ func (c *KubeIngressController) Get() { c.AbortBadRequestFormat("Cluster") return } - res, err := ingress.GetServiceDetail(k8sClinet, name, namespace) + res, err := ingress.GetDetail(k8sClinet, name, namespace) if err != nil { logs.Error("get ingress error cluster: %s, namespace: %s", cluster, namespace) c.HandleError(err) @@ -129,7 +130,7 @@ func (c *KubeIngressController) Offline() { c.AbortBadRequestFormat("Cluster") return } - if err = ingress.DeleteService(k8sClient, name, namespace); err != nil { + if err = ingress.Delete(k8sClient, name, namespace); err != nil { logs.Error("delete ingress: %s in namespace: %s, error: %s", name, namespace, err.Error()) c.HandleError(err) return diff --git a/src/backend/models/response/response.go b/src/backend/models/response/response.go index b8aff389d..711d97f6b 100644 --- a/src/backend/models/response/response.go +++ b/src/backend/models/response/response.go @@ -98,6 +98,7 @@ type Resource struct { Cluster string `json:"cluster,omitempty"` Status models.ReleaseStatus `json:"status,omitempty"` Message string `json:"message,omitempty"` + Object interface{} `json:"object,omitempty"` // 用于存储 kubernetes 资源对象的配置细节 } // OpenAPI 通用 失败 返回接口 diff --git a/src/backend/resources/ingress/ingress.go b/src/backend/resources/ingress/ingress.go index a4c9f5d64..b20ff7f00 100644 --- a/src/backend/resources/ingress/ingress.go +++ b/src/backend/resources/ingress/ingress.go @@ -7,7 +7,7 @@ import ( "k8s.io/client-go/kubernetes" ) -func CreateOrUpdateService(c *kubernetes.Clientset, ingress *k8sv1beta1.Ingress) (*k8sv1beta1.Ingress, error) { +func CreateOrUpdate(c *kubernetes.Clientset, ingress *k8sv1beta1.Ingress) (*k8sv1beta1.Ingress, error) { old, err := c.ExtensionsV1beta1().Ingresses(ingress.Namespace).Get(ingress.Name, metaV1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { @@ -19,7 +19,7 @@ func CreateOrUpdateService(c *kubernetes.Clientset, ingress *k8sv1beta1.Ingress) return c.ExtensionsV1beta1().Ingresses(ingress.Namespace).Update(old) } -func GetServiceDetail(c *kubernetes.Clientset, name, namespace string) (*k8sv1beta1.Ingress, error) { +func GetDetail(c *kubernetes.Clientset, name, namespace string) (*k8sv1beta1.Ingress, error) { ingress, err := c.ExtensionsV1beta1().Ingresses(namespace).Get(name, metaV1.GetOptions{}) if err != nil { return nil, err @@ -27,6 +27,6 @@ func GetServiceDetail(c *kubernetes.Clientset, name, namespace string) (*k8sv1be return ingress, nil } -func DeleteService(c *kubernetes.Clientset, name, namespace string) error { +func Delete(c *kubernetes.Clientset, name, namespace string) error { return c.ExtensionsV1beta1().Ingresses(namespace).Delete(name, &metaV1.DeleteOptions{}) } From d4a034c5326c02a918de575499e39079630bcd9a Mon Sep 17 00:00:00 2001 From: chengyumeng <792400644@qq.com> Date: Tue, 11 Dec 2018 14:56:36 +0800 Subject: [PATCH 06/22] backend:when online service,webhook pass k8s infomation --- src/backend/controllers/kubernetes/service/service.go | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backend/controllers/kubernetes/service/service.go b/src/backend/controllers/kubernetes/service/service.go index 3e3482f1a..484d96d7b 100644 --- a/src/backend/controllers/kubernetes/service/service.go +++ b/src/backend/controllers/kubernetes/service/service.go @@ -102,6 +102,7 @@ func (c *KubeServiceController) Deploy() { Cluster: publishHistory.Cluster, Status: publishHistory.Status, Message: publishHistory.Message, + Object: kubeService, }) c.Success("ok") From 67893a2c06f775d89d092c9cecbe9c6690c76ac3 Mon Sep 17 00:00:00 2001 From: chengyumeng <792400644@qq.com> Date: Wed, 12 Dec 2018 12:14:45 +0800 Subject: [PATCH 07/22] backend:fix code review --- .../controllers/kubernetes/ingress/ingress.go | 6 +++--- src/backend/models/hookevent/event.go | 14 +++++++------- src/backend/models/namespace_user.go | 6 +++--- src/backend/resources/ingress/ingress.go | 6 +++--- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/backend/controllers/kubernetes/ingress/ingress.go b/src/backend/controllers/kubernetes/ingress/ingress.go index 713767143..3c760b087 100644 --- a/src/backend/controllers/kubernetes/ingress/ingress.go +++ b/src/backend/controllers/kubernetes/ingress/ingress.go @@ -69,7 +69,7 @@ func (c *KubeIngressController) Deploy() { logs.Critical("insert log into database failed: %s", err) } }() - _, err = ingress.CreateOrUpdate(k8sClient, &kubeIngress) + _, err = ingress.CreateOrUpdateIngress(k8sClient, &kubeIngress) if err != nil { publishHistory.Status = models.ReleaseFailure publishHistory.Message = err.Error() @@ -112,7 +112,7 @@ func (c *KubeIngressController) Get() { c.AbortBadRequestFormat("Cluster") return } - res, err := ingress.GetDetail(k8sClinet, name, namespace) + res, err := ingress.GetIngressDetail(k8sClinet, name, namespace) if err != nil { logs.Error("get ingress error cluster: %s, namespace: %s", cluster, namespace) c.HandleError(err) @@ -130,7 +130,7 @@ func (c *KubeIngressController) Offline() { c.AbortBadRequestFormat("Cluster") return } - if err = ingress.Delete(k8sClient, name, namespace); err != nil { + if err = ingress.DeleteIngress(k8sClient, name, namespace); err != nil { logs.Error("delete ingress: %s in namespace: %s, error: %s", name, namespace, err.Error()) c.HandleError(err) return diff --git a/src/backend/models/hookevent/event.go b/src/backend/models/hookevent/event.go index e417b1c66..a761c366b 100644 --- a/src/backend/models/hookevent/event.go +++ b/src/backend/models/hookevent/event.go @@ -11,26 +11,26 @@ var ( EventDeployment = &HookEvent{ Key: "deployment", - Name: "部署", - Description: "部署相关动作行为,如创建、上下线、实例数量调整等", + Name: "Deployment(部署)", + Description: "Related actions of \"deployment\", such as creation, online and offline, instance number adjustment, etc.", } EventService = &HookEvent{ Key: "service", - Name: "负载均衡", - Description: "负载均衡相关动作行为,如上下线等", + Name: "Service(负载均衡)", + Description: "Related actions of \"Service\", such as the above online, offline, etc.", } EventIngress = &HookEvent{ Key: "ingress", Name: "Ingress", - Description: "Ingress 相关动作行为,如上下线等", + Description: "Related actions of \"Ingress\", such as the above online, offline, etc.", } EventMember = &HookEvent{ Key: "member", - Name: "成员", - Description: "项目/部门成员增删或权限变更", + Name: "Member(成员)", + Description: "Monitor the additions, deletions, or changes in permissions of members of a application or namespace.", } ) diff --git a/src/backend/models/namespace_user.go b/src/backend/models/namespace_user.go index 3cc12a55a..5b7804d00 100644 --- a/src/backend/models/namespace_user.go +++ b/src/backend/models/namespace_user.go @@ -119,9 +119,9 @@ func (n *namespaceUserModel) GetById(id int64, allGroupFlag bool) (v *NamespaceU if err = Ormer().Read(v); err != nil { return nil, err } - v.User, err = UserModel.GetUserById(v.User.Id) - if err != nil { - return nil, err + _, err = Ormer().LoadRelated(v, "User") + if err == nil { + return v, nil } if allGroupFlag { namespaceUsers := []NamespaceUser{} diff --git a/src/backend/resources/ingress/ingress.go b/src/backend/resources/ingress/ingress.go index b20ff7f00..d81b08fb8 100644 --- a/src/backend/resources/ingress/ingress.go +++ b/src/backend/resources/ingress/ingress.go @@ -7,7 +7,7 @@ import ( "k8s.io/client-go/kubernetes" ) -func CreateOrUpdate(c *kubernetes.Clientset, ingress *k8sv1beta1.Ingress) (*k8sv1beta1.Ingress, error) { +func CreateOrUpdateIngress(c *kubernetes.Clientset, ingress *k8sv1beta1.Ingress) (*k8sv1beta1.Ingress, error) { old, err := c.ExtensionsV1beta1().Ingresses(ingress.Namespace).Get(ingress.Name, metaV1.GetOptions{}) if err != nil { if errors.IsNotFound(err) { @@ -19,7 +19,7 @@ func CreateOrUpdate(c *kubernetes.Clientset, ingress *k8sv1beta1.Ingress) (*k8sv return c.ExtensionsV1beta1().Ingresses(ingress.Namespace).Update(old) } -func GetDetail(c *kubernetes.Clientset, name, namespace string) (*k8sv1beta1.Ingress, error) { +func GetIngressDetail(c *kubernetes.Clientset, name, namespace string) (*k8sv1beta1.Ingress, error) { ingress, err := c.ExtensionsV1beta1().Ingresses(namespace).Get(name, metaV1.GetOptions{}) if err != nil { return nil, err @@ -27,6 +27,6 @@ func GetDetail(c *kubernetes.Clientset, name, namespace string) (*k8sv1beta1.Ing return ingress, nil } -func Delete(c *kubernetes.Clientset, name, namespace string) error { +func DeleteIngress(c *kubernetes.Clientset, name, namespace string) error { return c.ExtensionsV1beta1().Ingresses(namespace).Delete(name, &metaV1.DeleteOptions{}) } From 558efc316fabba68aa2e462519f6bef01fdd4862 Mon Sep 17 00:00:00 2001 From: BennieMeng Date: Wed, 12 Dec 2018 14:56:25 +0800 Subject: [PATCH 08/22] frontend: select component optimize --- .../node/list-nodes/list-nodes.component.html | 3 +- .../list-persistentvolume.component.html | 3 +- .../cronjob/list-job/list-job.component.html | 3 +- .../overview/overview.component.ts | 6 +- .../shared/paginate/paginate.component.html | 8 +- .../app/shared/paginate/paginate.component.ts | 27 +- .../select/option/option.component.scss | 16 +- .../app/shared/select/select.component.html | 5 +- .../app/shared/select/select.component.scss | 4 +- .../src/app/shared/select/select.component.ts | 325 +++++++++++++++--- 10 files changed, 318 insertions(+), 82 deletions(-) diff --git a/src/frontend/src/app/admin/node/list-nodes/list-nodes.component.html b/src/frontend/src/app/admin/node/list-nodes/list-nodes.component.html index 5380716d0..2a4d68818 100644 --- a/src/frontend/src/app/admin/node/list-nodes/list-nodes.component.html +++ b/src/frontend/src/app/admin/node/list-nodes/list-nodes.component.html @@ -104,8 +104,7 @@ - + {{pagesize}} diff --git a/src/frontend/src/app/admin/persistentvolume/list-persistentvolume/list-persistentvolume.component.html b/src/frontend/src/app/admin/persistentvolume/list-persistentvolume/list-persistentvolume.component.html index 132d65d18..fe855dc5f 100644 --- a/src/frontend/src/app/admin/persistentvolume/list-persistentvolume/list-persistentvolume.component.html +++ b/src/frontend/src/app/admin/persistentvolume/list-persistentvolume/list-persistentvolume.component.html @@ -99,8 +99,7 @@ - + {{pagesize}} diff --git a/src/frontend/src/app/portal/cronjob/list-job/list-job.component.html b/src/frontend/src/app/portal/cronjob/list-job/list-job.component.html index 4d84a3702..13a34d37c 100644 --- a/src/frontend/src/app/portal/cronjob/list-job/list-job.component.html +++ b/src/frontend/src/app/portal/cronjob/list-job/list-job.component.html @@ -58,8 +58,7 @@ - + {{pagesize}} {{pagination.firstItem + 1}} - {{pagination.lastItem + 1}} of {{pagination.totalItems}} diff --git a/src/frontend/src/app/portal/namespace-report/overview/overview.component.ts b/src/frontend/src/app/portal/namespace-report/overview/overview.component.ts index 020297254..28bb53400 100644 --- a/src/frontend/src/app/portal/namespace-report/overview/overview.component.ts +++ b/src/frontend/src/app/portal/namespace-report/overview/overview.component.ts @@ -26,9 +26,7 @@ export class OverviewComponent implements OnInit { resources: object = new Object(); clusters: string[] = []; clusterList: Cluster[] = []; - showNumber: number = 10; - - + showNumber = 10; resourceCountMap: any; readonly deployment = KubeApiTypeDeployment; readonly cronJob = KubeApiTypeCronJob; @@ -76,7 +74,7 @@ export class OverviewComponent implements OnInit { response => { this.resources = response.data; this.clusterList = Object.keys(this.resources).map(item => { - let a = new Cluster(); + const a = new Cluster(); a['cluster'] = item; a['resource'] = this.resources[item]; return a; diff --git a/src/frontend/src/app/shared/paginate/paginate.component.html b/src/frontend/src/app/shared/paginate/paginate.component.html index c6b13baa6..e168ec0eb 100644 --- a/src/frontend/src/app/shared/paginate/paginate.component.html +++ b/src/frontend/src/app/shared/paginate/paginate.component.html @@ -1,14 +1,14 @@ - + {{pagesize}} - + {{i}} / {{lastPage}} {{'PAGE.PAGE' | translate}} diff --git a/src/frontend/src/app/shared/paginate/paginate.component.ts b/src/frontend/src/app/shared/paginate/paginate.component.ts index e364fbd6e..ed42bb665 100644 --- a/src/frontend/src/app/shared/paginate/paginate.component.ts +++ b/src/frontend/src/app/shared/paginate/paginate.component.ts @@ -16,25 +16,23 @@ export class PaginateComponent implements OnInit { */ private _current: number; @Input() total: number; - @Input() set currentPage(value) { this._current = value; - }; - + } @Input() pageSizes: Array; - @Input() rate: number = 1; - @Input() _size: number = 10; - @Input() localSave: boolean = true; + @Input() rate = 1; + @Input() _size = 10; + @Input() localSave = true; @Output() sizeChange = new EventEmitter(); @Output() currentPageChange = new EventEmitter(); get current() { return this._current || 1; - }; + } set current(value: number) { this.currentPageChange.emit(value); - }; + } get lastPage(): number { try { @@ -46,7 +44,7 @@ export class PaginateComponent implements OnInit { get pageList(): Array { try { - let pageList = Array(); + const pageList = Array(); for (let key = 1; key <= this.lastPage; key++) { pageList.push(key); } @@ -58,7 +56,7 @@ export class PaginateComponent implements OnInit { get showSize() { return this.pageSizes !== undefined; - }; + } constructor( private storage: StorageService, @@ -68,7 +66,7 @@ export class PaginateComponent implements OnInit { ngOnInit() { if (this.localSave && this.pageSizes) { - this._size = parseInt(this.storage.get('pagesize')) * this.rate || 10 * this.rate; + this._size = parseInt(this.storage.get('pagesize'), 10) * this.rate || 10 * this.rate; if (this.pageSizes.indexOf(this._size) === -1) { this.pageSizes.push(this._size); this.pageSizes.sort((a, b) => a - b); @@ -80,9 +78,12 @@ export class PaginateComponent implements OnInit { return this._size; } - set size(value) { + set size(value: any) { + value = parseInt(value, 10); this._size = value; - if (this.localSave && this.pageSizes && this.pageSizes.indexOf(value) > -1) this.storage.save('pagesize', this._size / this.rate); + if (this.localSave && this.pageSizes && this.pageSizes.indexOf(value) > -1) { + this.storage.save('pagesize', this._size / this.rate); + } this.sizeChange.emit(this._size); } diff --git a/src/frontend/src/app/shared/select/option/option.component.scss b/src/frontend/src/app/shared/select/option/option.component.scss index a05d541bf..bd5be9ab8 100644 --- a/src/frontend/src/app/shared/select/option/option.component.scss +++ b/src/frontend/src/app/shared/select/option/option.component.scss @@ -3,9 +3,23 @@ height: 25px; line-height: 25px; text-align: left; - padding: 0 6px; + padding: 0 30px 0 6px; cursor: pointer; + font-family: monospace; + position: relative; + &.active:after{ + content: ''; + position: absolute; + right: 0; + top: 0; + width: 30px; + height: 100%; + background: center / 50% no-repeat url('data:image/svg+xml;utf8,%3Csvg%20width%3D%2214%22%20height%3D%2214%22%20fill%3D%22none%22%20viewBox%3D%220%2C%200%2C%2030%2C%2030%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%20%20%20%20%20%20%3Crect%20width%3D%2230%22%20height%3D%2230%22%3E%3C%2Frect%3E%20%20%20%20%20%20%3Cpath%20d%3D%22M%205%2015%20L%209%2020%20Q%2010.5%2022%2C%2011%2021%20L%2025%205%22%20stroke%3D%22%23377aec%22%20stroke-width%3D%223%22%2F%3E%20%20%20%20%20%20%3Ccircle%20cx%3D%225%22%20cy%3D%2215%22%20r%3D%221.5%22%3E%3C%2Fcircle%3E%20%20%20%20%20%20%3Ccircle%20cx%3D%2225%22%20cy%3D%225%22%20r%3D%221.5%22%3E%3C%2Fcircle%3E%20%20%20%20%3C%2Fsvg%3E'); + } + &.hide{ + display: none; + } &:hover { background: rgba(232, 237, 246, .45); } diff --git a/src/frontend/src/app/shared/select/select.component.html b/src/frontend/src/app/shared/select/select.component.html index 1a88480f2..499884c82 100644 --- a/src/frontend/src/app/shared/select/select.component.html +++ b/src/frontend/src/app/shared/select/select.component.html @@ -1,10 +1,11 @@ + (input)="inputEvent($event)" [readonly]="read" [cursor]="cursor"> -
+
+
= new Set(); barState = 'hide'; - showBox = false; top = 0; barHeight: number; maxTrans: number; wrap: HTMLElement; svg: HTMLElement; _options: QueryList; + globalEventList: Array = new Array(); barEventList: Array = new Array(); inputEventList: Array = new Array(); itemClickEventList: Array = new Array(); clickStart: number = null; barTopCache: number; marginRight: number; - @Input('cursor') cursor = 'auto'; - @Input('readonly') readonly = false; - @Input('type') type = ''; + // store text -> value; + listText: any; + listValue: any; + dire: string; + multText = ''; + @Input('searchable') searchable; + get search(): boolean { + return (this.searchable === undefined || this.searchable === false) ? false : true; + } + @Input('inputable') inputable; + get input(): boolean { + return (this.inputable === undefined || this.inputable === false) ? false : true; + } + @Input('multiple') multiple; + get mult(): boolean { + return (this.multiple === undefined || this.multiple === false) ? false : true; + } + @Input('readonly') readonly; + get read(): boolean { + return !this.mult && (this.input || (this.readonly !== undefined && this.readonly === false)) ? false : true; + } + @Input('direction') direction = 'auto'; + @Input('cursor') cursor = 'pointer'; @Input('placeholder') placeholder = ''; @Output() change = new EventEmitter(); updateEmit = (_: any) => {}; @@ -74,20 +117,62 @@ export class SelectComponent implements AfterViewInit, ControlValueAccessor { set value(value: any) { if (this._value !== value) { - if (this.type === 'page') { - this._value = parseInt(value, 10) || null; + this._value = value; + if (this.mult) { + this.updateValue(this.stringToValue(value)); + } else if (this.input) { if (this._value) { - this.updateValue(this._value); + // pagination 下为了保证不为null,0 报错 + this.updateValue(this.listText[this._value] !== undefined ? this.listText[this._value] : this._value); } } else { - this._value = value; - this.updateValue(this._value); + if (!this.listText) { + return; + } + this.updateValue(this.listText[this._value] !== undefined ? this.listText[this._value] : ''); } + this.setActive(this._value); } } - inputEvent(evt) { - evt.target.value = this.value; + get filterValue() { + return this._filterValue; + } + + set filterValue(value: any) { + if (this._filterValue !== value) { + this._filterValue = value; + if (this.search) { + this._options.forEach(item => { + if (value === null || value === undefined || item.el.nativeElement.innerText.indexOf(value) > -1) { + item.el.nativeElement.classList.remove('hide'); + } else { + item.el.nativeElement.classList.add('hide'); + } + }); + } + } + } + + get showBox(): boolean { + return this._showBox; + } + + set showBox(show: boolean) { + this._showBox = show; + if (show) { + setTimeout(() => { + this.resizeEvent(); + this.globalEventList.push( + this.eventManager.addGlobalEventListener('window', 'resize', this.resizeEvent.bind(this)), + this.eventManager.addEventListener(this.document.querySelector('.content-area'), 'scroll', this.resizeEvent.bind(this)) + ); + }, 100); + } else { + this.globalEventList.forEach(event => { + event(); + }); + } } constructor( @@ -98,13 +183,10 @@ export class SelectComponent implements AfterViewInit, ControlValueAccessor { ) { } - @ContentChildren(OptionComponent) - set options(options: QueryList) { - this._options = options; - this.removeCick(); - this.addClick(options); - if (this.showBox) { - this.initBar(); + ngOnInit() { + this.dire = this.direction === 'top' ? 'top' : 'bottom'; + if (this.mult && this.input) { + console.warn('inputable 属性和 searchable 不能共用'); } } @@ -113,39 +195,65 @@ export class SelectComponent implements AfterViewInit, ControlValueAccessor { this.marginRight = -this.scrollService.scrollBarWidth; } - isClickBox(target: Element): boolean { - while (target.tagName.toLowerCase() !== 'body') { - if (target.tagName.toLowerCase() === 'wayne-select') { - return true; - } - target = target.parentElement; - } - return false; - } - - get barTop() { - return `translateY(${this.top}%)`; + inputEvent(evt) { + evt.target.value = this.value; } - - writeValue(value: any): void { - if (value !== this.value) { - this.value = value; + /** + * option + * */ + @ContentChildren(OptionComponent) + set options(options: QueryList) { + this._options = options; + this.removeCick(); + this.initOption(options); + this.setActive(this.value); + if (this.showBox) { + this.initBar(); } } - registerOnChange(fn: (_: any) => {}): void { - this.updateEmit = fn; - } - - registerOnTouched(fn: any): void { - } - - addClick(options: QueryList) { + initOption(options: QueryList) { + this.listText = {}; + this.listValue = {}; options.forEach((item, index) => { + const element = item.el.nativeElement; + this.listText[element.innerText] = item.value; + this.listValue[item.value] = element.innerText; this.itemClickEventList.push( - this.eventManager.addEventListener(item.el.nativeElement, 'click', this.clickEvent.bind(this, item.value, options)) + this.eventManager.addEventListener(element, 'click', this.clickEvent.bind(this, element.innerText, options)) ); }); + // async init option function + if (this.value !== '') { + setTimeout(() => { + if (this.mult) { + this.value = this.valueToString(); + } else { + this.value = this.listText[this.value] === undefined && this.listValue[this.value] !== undefined ? this.listValue : this.value; + } + }); + } + } + + setActive(value: string) { + if (value === null) { + return; + } + const textList = new Set(); + if (this.mult) { + this.multText.split(splitString).forEach(item => { + textList.add(this.listText[item]); + }); + } else { + textList.add(this.listText[value]); + } + this._options.forEach(item => { + if (textList.has(item.value)) { + item.el.nativeElement.classList.add('active'); + } else { + item.el.nativeElement.classList.remove('active'); + } + }); } removeCick() { @@ -155,12 +263,36 @@ export class SelectComponent implements AfterViewInit, ControlValueAccessor { this.itemClickEventList = []; } - clickEvent(value, options: QueryList, event) { + isClickBox(target: Element): boolean { + while (target && target.tagName.toLowerCase() !== 'body') { + if (target.tagName.toLowerCase() === 'wayne-select') { + return true; + } + target = target.parentElement; + } + return false; + } + + get barTop() { + return `translateY(${this.top}%)`; + } + + clickEvent(text, options: QueryList, event) { this.removeStyle(options); event.target.style.background = 'rgba(232, 237, 246, .45)'; - this.value = value; - this.destoryBar(); - this.showBox = false; + if (this.mult) { + const value = this.listText[text]; + if (this._values.has(value)) { + this._values.delete(value); + } else { + this._values.add(value); + } + this.value = this.valueToString(); + } else { + this.value = text; + this.destoryBar(); + this.showBox = false; + } } updateValue(value: any) { @@ -191,12 +323,106 @@ export class SelectComponent implements AfterViewInit, ControlValueAccessor { } } + resizeEvent() { + if (this.direction === 'auto') { + // 去除 header 高度 + const headerHeight = 60; + const bodyHeight = this.document.body.offsetHeight; + const target = this.document.querySelector('.select-box'); + if (!target) { + return; + } + const height = target.offsetHeight; + const top = target.getBoundingClientRect().top; + const bottom = bodyHeight - top - height; + if (this.dire === 'top') { + if (bottom > height + 36 && top - headerHeight <= 0) { + this.dire = 'bottom'; + } + } else { + if (top - headerHeight > height + 36 && bottom <= 0) { + this.dire = 'top'; + } + } + } + } + removeStyle(options: QueryList) { options.forEach(item => { item.el.nativeElement.style.background = ''; }); } + /** + * mult 下 this._values -> string + * 全局变量 this._values, this.listValue + * */ + valueToString() { + const arr = Array.from(this._values).map(res => { + return this.listValue[res] ? this.listValue[res] : res; + }); + this.multText = arr.join(splitString); + return arr.join(', '); + } + /** + * mult 下 string -> array + * 全局变量 this._values, this.listText + */ + stringToValue(text: string) { + const result = []; + this.multText.split(splitString).forEach(item => { + const value = this.listText[item] !== undefined + ? this.listText[item] + : this.listValue[item] !== undefined + ? this.listValue[item] + : item; + result.push(value); + }); + return result; + } + + /** + * update value; + * */ + writeValue(value: any): void { + if (this.mult) { + // array -> string; + if (value && value.toString() !== this.value) { + if (Object.prototype.toString.call(value) === '[object Array]') { + this._values.clear(); + value.forEach(item => { + this._values.add(item); + }); + this.value = this.valueToString(); + } else { + this.value = ''; + } + } else { + this.value = ''; + } + } else { + // value -> text; + if (value !== this.value) { + if (this.input) { + this.value = value; + } else { + if (this.listValue) { + this.value = this.listValue[value] !== undefined ? this.listValue[value] : value; + } else { + this.value = value; + } + } + } + } + } + + registerOnChange(fn: (_: any) => {}): void { + this.updateEmit = fn; + } + + registerOnTouched(fn: any): void { + } + /** * bar 移动范围(0 ~ box - bar) * box 移动范围(0 ~ wrap - box) @@ -213,7 +439,6 @@ export class SelectComponent implements AfterViewInit, ControlValueAccessor { this.top = Number((target.scrollTop / target.clientHeight * 100).toFixed(2)); } - initBar() { this.svg.style.transform = 'rotateZ(90deg)'; this.wrap = this.el.nativeElement.querySelector('.option-box'); From 330fbff7ffdbb1ad515bb4a555ebc74b73944805 Mon Sep 17 00:00:00 2001 From: chengyumeng <792400644@qq.com> Date: Wed, 12 Dec 2018 14:57:49 +0800 Subject: [PATCH 09/22] backend:add the api of get pod info from ip. --- src/backend/controllers/openapi/openapi.go | 1 + src/backend/controllers/openapi/pod.go | 63 ++++++++++++++++++++++ src/backend/resources/pod/pod.go | 15 ++++++ 3 files changed, 79 insertions(+) diff --git a/src/backend/controllers/openapi/openapi.go b/src/backend/controllers/openapi/openapi.go index 93fbafb8e..2d3c3420b 100644 --- a/src/backend/controllers/openapi/openapi.go +++ b/src/backend/controllers/openapi/openapi.go @@ -45,6 +45,7 @@ import ( const ( GetPodInfoAction = "GET_POD_INFO" + GetPodInfoFromIPAction = "GET_POD_INFO_FROM_IP" GetResourceInfoAction = "GET_RESOURCE_INFO" GetDeploymentStatusAction = "GET_DEPLOYMENT_STATUS" UpgradeDeploymentAction = "UPGRADE_DEPLOYMENT" diff --git a/src/backend/controllers/openapi/pod.go b/src/backend/controllers/openapi/pod.go index 81d011bc9..6265fbe33 100644 --- a/src/backend/controllers/openapi/pod.go +++ b/src/backend/controllers/openapi/pod.go @@ -4,6 +4,8 @@ import ( "fmt" "net/http" + "strings" + "github.com/Qihoo360/wayne/src/backend/client" "github.com/Qihoo360/wayne/src/backend/models" "github.com/Qihoo360/wayne/src/backend/models/response" @@ -32,6 +34,17 @@ type PodInfoParam struct { Cluster string `json:"cluster"` } +// swagger:parameters PodInfoFromIPParam +type PodInfoFromIPParam struct { + // A list of ip. + // in: query + // Required: true + IPS string `json:"ips"` + ips []string `json:"-"` + // Required: true + Cluster string `json:"cluster"` +} + // swagger:route GET /get_pod_info pod PodInfoParam // // 用于获取线上所有 pod 中包含请求条件中 labelSelector 指定的特定 label 的 pod @@ -77,3 +90,53 @@ func (c *OpenAPIController) GetPodInfo() { } c.HandleResponse(podList.Body) } + +// swagger:route GET /get_pod_info_from_ip pod PodInfoFromIPParam +// +// 用于通过线上 kubernetes Pod IP 反查对应 Pod 信息的接口 +// +// 返回 每个 pod 的 pod IP 和 所有 label 列表。 +// 需要绑定全局 apikey 使用。该接口的权限控制为只能使用全局 apikey 的原因是查询条件为 IP ,是对所有 app 的 条件过滤。 +// +// Responses: +// 200: resppodlist +// 401: responseState +// 500: responseState +// @router /get_pod_info_from_ip [get] +func (c *OpenAPIController) GetPodInfoFromIP() { + if !c.CheckoutRoutePermission(GetPodInfoFromIPAction) { + return + } + if c.APIKey.Type != models.GlobalAPIKey { + c.AddErrorAndResponse("You can only use global APIKey in this action!", http.StatusUnauthorized) + return + } + params := PodInfoFromIPParam{IPS: c.GetString("ips"), Cluster: c.GetString("cluster")} + if params.Cluster == "" { + c.AddErrorAndResponse("Invalid cluster parameter:must required!", http.StatusBadRequest) + return + } + params.ips = strings.Split(params.IPS, ",") + clis := client.Clients() + if clis[params.Cluster] == nil { + c.AddErrorAndResponse("Invalid cluster parameter:not exist!", http.StatusBadRequest) + return + } + pods, err := pod.GetAllPods(clis[params.Cluster]) + if err != nil { + logs.Error(fmt.Sprintf("Failed to parse metadata: %s", err.Error())) + c.AddErrorAndResponse(fmt.Sprintf("Maybe a problematic k8s cluster(%s)!", params.Cluster), http.StatusInternalServerError) + return + } + podList := resppodlist{} + podList.Body.Code = http.StatusOK + for _, p := range pods { + for _, ip := range params.ips { + if ip == p.PodIp { + podList.Body.Pods = append(podList.Body.Pods, response.Pod{Labels: p.Labels, PodIp: p.PodIp}) + } + } + } + c.HandleResponse(podList.Body) + +} diff --git a/src/backend/resources/pod/pod.go b/src/backend/resources/pod/pod.go index cc6f8aebc..5cb440cc1 100644 --- a/src/backend/resources/pod/pod.go +++ b/src/backend/resources/pod/pod.go @@ -86,6 +86,21 @@ func GetAllPodByLabelSelector(cli *kubernetes.Clientset, labelSelector string) ( return pods, nil } +func GetAllPods(cli *kubernetes.Clientset) ([]*Pod, error) { + podList, err := cli.CoreV1().Pods(metaV1.NamespaceAll).List(metaV1.ListOptions{}) + if err != nil { + return nil, err + } + pods := make([]*Pod, 0) + for _, pod := range podList.Items { + pods = append(pods, &Pod{ + Labels: pod.Labels, + PodIp: pod.Status.PodIP, + }) + } + return pods, nil +} + func GetPodsBySelector(cli *kubernetes.Clientset, namespace, labelSelector string) ([]v1.Pod, error) { podList, err := cli.CoreV1().Pods(namespace).List(metaV1.ListOptions{LabelSelector: labelSelector}) if err != nil { From 198adf9a4b811aaba46292e94c1847a3e86e4881 Mon Sep 17 00:00:00 2001 From: chengyumeng <792400644@qq.com> Date: Wed, 12 Dec 2018 16:31:33 +0800 Subject: [PATCH 10/22] backend:fix api use cache --- src/backend/controllers/openapi/pod.go | 10 +++++----- src/backend/resources/pod/pod.go | 19 ++----------------- .../commentsRouter_controllers_openapi.go | 8 ++++++++ 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/src/backend/controllers/openapi/pod.go b/src/backend/controllers/openapi/pod.go index 6265fbe33..9b4aca13e 100644 --- a/src/backend/controllers/openapi/pod.go +++ b/src/backend/controllers/openapi/pod.go @@ -117,12 +117,12 @@ func (c *OpenAPIController) GetPodInfoFromIP() { return } params.ips = strings.Split(params.IPS, ",") - clis := client.Clients() - if clis[params.Cluster] == nil { + manager, err := client.Manager(params.Cluster) + if err != nil { c.AddErrorAndResponse("Invalid cluster parameter:not exist!", http.StatusBadRequest) return } - pods, err := pod.GetAllPods(clis[params.Cluster]) + pods := pod.GetPodsBySelectorFromCache(manager.Indexer, "", nil) if err != nil { logs.Error(fmt.Sprintf("Failed to parse metadata: %s", err.Error())) c.AddErrorAndResponse(fmt.Sprintf("Maybe a problematic k8s cluster(%s)!", params.Cluster), http.StatusInternalServerError) @@ -132,8 +132,8 @@ func (c *OpenAPIController) GetPodInfoFromIP() { podList.Body.Code = http.StatusOK for _, p := range pods { for _, ip := range params.ips { - if ip == p.PodIp { - podList.Body.Pods = append(podList.Body.Pods, response.Pod{Labels: p.Labels, PodIp: p.PodIp}) + if ip == p.Status.PodIP { + podList.Body.Pods = append(podList.Body.Pods, response.Pod{Labels: p.Labels, PodIp: p.Status.PodIP}) } } } diff --git a/src/backend/resources/pod/pod.go b/src/backend/resources/pod/pod.go index 5cb440cc1..b68bb7a95 100644 --- a/src/backend/resources/pod/pod.go +++ b/src/backend/resources/pod/pod.go @@ -57,11 +57,11 @@ func GetPodsBySelectorFromCache(indexer *client.CacheIndexer, namespace string, if !ok { continue } - if namespace != cachePod.Namespace { + if namespace != "" && namespace != cachePod.Namespace { continue } - if !common.CompareLabels(labels, cachePod.Labels) { + if labels != nil && !common.CompareLabels(labels, cachePod.Labels) { continue } @@ -86,21 +86,6 @@ func GetAllPodByLabelSelector(cli *kubernetes.Clientset, labelSelector string) ( return pods, nil } -func GetAllPods(cli *kubernetes.Clientset) ([]*Pod, error) { - podList, err := cli.CoreV1().Pods(metaV1.NamespaceAll).List(metaV1.ListOptions{}) - if err != nil { - return nil, err - } - pods := make([]*Pod, 0) - for _, pod := range podList.Items { - pods = append(pods, &Pod{ - Labels: pod.Labels, - PodIp: pod.Status.PodIP, - }) - } - return pods, nil -} - func GetPodsBySelector(cli *kubernetes.Clientset, namespace, labelSelector string) ([]v1.Pod, error) { podList, err := cli.CoreV1().Pods(namespace).List(metaV1.ListOptions{LabelSelector: labelSelector}) if err != nil { diff --git a/src/backend/routers/commentsRouter_controllers_openapi.go b/src/backend/routers/commentsRouter_controllers_openapi.go index ac322e587..4efb2739b 100644 --- a/src/backend/routers/commentsRouter_controllers_openapi.go +++ b/src/backend/routers/commentsRouter_controllers_openapi.go @@ -23,6 +23,14 @@ func init() { MethodParams: param.Make(), Params: nil}) + beego.GlobalControllerRouter["github.com/Qihoo360/wayne/src/backend/controllers/openapi:OpenAPIController"] = append(beego.GlobalControllerRouter["github.com/Qihoo360/wayne/src/backend/controllers/openapi:OpenAPIController"], + beego.ControllerComments{ + Method: "GetPodInfoFromIP", + Router: `/get_pod_info_from_ip`, + AllowHTTPMethods: []string{"get"}, + MethodParams: param.Make(), + Params: nil}) + beego.GlobalControllerRouter["github.com/Qihoo360/wayne/src/backend/controllers/openapi:OpenAPIController"] = append(beego.GlobalControllerRouter["github.com/Qihoo360/wayne/src/backend/controllers/openapi:OpenAPIController"], beego.ControllerComments{ Method: "GetResourceInfo", From d639971383068fd1af27e912261a3e66d72d820a Mon Sep 17 00:00:00 2001 From: chengyumeng <792400644@qq.com> Date: Wed, 12 Dec 2018 16:51:44 +0800 Subject: [PATCH 11/22] backend:remove error line --- src/backend/controllers/openapi/pod.go | 1 - 1 file changed, 1 deletion(-) diff --git a/src/backend/controllers/openapi/pod.go b/src/backend/controllers/openapi/pod.go index 9b4aca13e..fd20670c4 100644 --- a/src/backend/controllers/openapi/pod.go +++ b/src/backend/controllers/openapi/pod.go @@ -3,7 +3,6 @@ package openapi import ( "fmt" "net/http" - "strings" "github.com/Qihoo360/wayne/src/backend/client" From 0feef1dc0ac8fd9983910573105afe6214f4ab2c Mon Sep 17 00:00:00 2001 From: chengyumeng <792400644@qq.com> Date: Wed, 12 Dec 2018 16:56:36 +0800 Subject: [PATCH 12/22] backend:array -> map --- src/backend/controllers/openapi/pod.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/backend/controllers/openapi/pod.go b/src/backend/controllers/openapi/pod.go index fd20670c4..9507fb82e 100644 --- a/src/backend/controllers/openapi/pod.go +++ b/src/backend/controllers/openapi/pod.go @@ -38,8 +38,8 @@ type PodInfoFromIPParam struct { // A list of ip. // in: query // Required: true - IPS string `json:"ips"` - ips []string `json:"-"` + IPS string `json:"ips"` + ips map[string]bool `json:"-"` // Required: true Cluster string `json:"cluster"` } @@ -115,7 +115,10 @@ func (c *OpenAPIController) GetPodInfoFromIP() { c.AddErrorAndResponse("Invalid cluster parameter:must required!", http.StatusBadRequest) return } - params.ips = strings.Split(params.IPS, ",") + params.ips = make(map[string]bool) + for _, ip := range strings.Split(params.IPS, ",") { + params.ips[ip] = true + } manager, err := client.Manager(params.Cluster) if err != nil { c.AddErrorAndResponse("Invalid cluster parameter:not exist!", http.StatusBadRequest) @@ -130,10 +133,8 @@ func (c *OpenAPIController) GetPodInfoFromIP() { podList := resppodlist{} podList.Body.Code = http.StatusOK for _, p := range pods { - for _, ip := range params.ips { - if ip == p.Status.PodIP { - podList.Body.Pods = append(podList.Body.Pods, response.Pod{Labels: p.Labels, PodIp: p.Status.PodIP}) - } + if params.ips[p.Status.PodIP] { + podList.Body.Pods = append(podList.Body.Pods, response.Pod{Labels: p.Labels, PodIp: p.Status.PodIP}) } } c.HandleResponse(podList.Body) From 5438947b7e565eebe305096b3f2b697bee9df1cd Mon Sep 17 00:00:00 2001 From: chengyumeng <792400644@qq.com> Date: Thu, 13 Dec 2018 11:15:47 +0800 Subject: [PATCH 13/22] backend:sql optimize --- src/backend/models/namespace_user.go | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/backend/models/namespace_user.go b/src/backend/models/namespace_user.go index 5b7804d00..291b31763 100644 --- a/src/backend/models/namespace_user.go +++ b/src/backend/models/namespace_user.go @@ -116,13 +116,9 @@ func (*namespaceUserModel) Add(m *NamespaceUser, allGroupFlag bool) (id int64, e func (n *namespaceUserModel) GetById(id int64, allGroupFlag bool) (v *NamespaceUser, err error) { v = &NamespaceUser{Id: id} - if err = Ormer().Read(v); err != nil { + if err = Ormer().QueryTable(TableNameNamespaceUser).Filter("Id", id).RelatedSel("User").One(v); err != nil { return nil, err } - _, err = Ormer().LoadRelated(v, "User") - if err == nil { - return v, nil - } if allGroupFlag { namespaceUsers := []NamespaceUser{} _, err := Ormer().QueryTable(TableNameNamespaceUser).Filter("Namespace", v.Namespace.Id).Filter("User", v.User.Id).RelatedSel("Group").All(&namespaceUsers) From 2458bd5fb72497029b677130700e441216f38b55 Mon Sep 17 00:00:00 2001 From: chengyumeng <792400644@qq.com> Date: Thu, 13 Dec 2018 11:26:45 +0800 Subject: [PATCH 14/22] frontend --- .../create-edit-namespace-user.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/src/app/portal/namespace-user/create-edit-namespace-user/create-edit-namespace-user.component.ts b/src/frontend/src/app/portal/namespace-user/create-edit-namespace-user/create-edit-namespace-user.component.ts index bc16dc1a1..56d39c400 100644 --- a/src/frontend/src/app/portal/namespace-user/create-edit-namespace-user/create-edit-namespace-user.component.ts +++ b/src/frontend/src/app/portal/namespace-user/create-edit-namespace-user/create-edit-namespace-user.component.ts @@ -32,7 +32,7 @@ export class CreateEditNamespaceUserComponent { checkOnGoing: boolean = false; isSubmitOnGoing: boolean = false; isNameValid: boolean = true; - componentName: string = '命名空间'; + componentName: string = '命名空间用户'; allGroups: Array; mapGroups: Map = new Map(); From 225f5636eaccde97fd888194616cce202d165871 Mon Sep 17 00:00:00 2001 From: chengyumeng <792400644@qq.com> Date: Thu, 13 Dec 2018 11:26:50 +0800 Subject: [PATCH 15/22] frontend:fix frontend error --- src/frontend/lib | 2 +- src/frontend/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/frontend/lib b/src/frontend/lib index 6e2cd9467..78e72f46e 160000 --- a/src/frontend/lib +++ b/src/frontend/lib @@ -1 +1 @@ -Subproject commit 6e2cd9467926b62334aec41f6e1a8f038e6786b4 +Subproject commit 78e72f46eb82945941c1fdaf813e7b8f57a628da diff --git a/src/frontend/package.json b/src/frontend/package.json index 2b0dbcd3f..627187fe2 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -72,7 +72,7 @@ "karma-jasmine-html-reporter": "^0.2.2", "protractor": "~5.3.0", "ts-node": "~5.0.1", - "tslint": "~5.9.1", + "tslint": "^5.9.1", "typescript": "~2.7.2", "webpack": "4.8.3" } From b159b8a85c430969706dffd1cc41e3f511f42f8c Mon Sep 17 00:00:00 2001 From: BennieMeng Date: Thu, 13 Dec 2018 16:49:48 +0800 Subject: [PATCH 16/22] Prompt the user background to assign Namespace machine room --- .../create-edit-configmaptpl.component.html | 1 + .../create-edit-cronjob.component.html | 1 + .../create-edit-daemonset.component.html | 1 + .../create-edit-deployment.component.html | 1 + .../create-edit-ingress.component.html | 1 + ...it-persistentvolumeclaimtpl.component.html | 1 + .../create-edit-secrettpl.component.html | 1 + .../create-edit-statefulset.component.html | 1 + src/frontend/src/assets/i18n/zh-Hans.json | 42 +++++++++++++++---- src/frontend/src/styles.scss | 4 ++ 10 files changed, 46 insertions(+), 8 deletions(-) diff --git a/src/frontend/src/app/portal/configmap/create-edit-configmaptpl/create-edit-configmaptpl.component.html b/src/frontend/src/app/portal/configmap/create-edit-configmaptpl/create-edit-configmaptpl.component.html index d8aec231e..0e36c2f19 100644 --- a/src/frontend/src/app/portal/configmap/create-edit-configmaptpl/create-edit-configmaptpl.component.html +++ b/src/frontend/src/app/portal/configmap/create-edit-configmaptpl/create-edit-configmaptpl.component.html @@ -6,6 +6,7 @@

{{'CONFIGMAP.CREATE_TMP' | translate}}

+ {{'CONFIGMAP.CREATE_EDIT_TMP.CLUSTER_MESSAGE' | translate}}
diff --git a/src/frontend/src/app/portal/cronjob/create-edit-cronjob/create-edit-cronjob.component.html b/src/frontend/src/app/portal/cronjob/create-edit-cronjob/create-edit-cronjob.component.html index e78431474..47d133f25 100644 --- a/src/frontend/src/app/portal/cronjob/create-edit-cronjob/create-edit-cronjob.component.html +++ b/src/frontend/src/app/portal/cronjob/create-edit-cronjob/create-edit-cronjob.component.html @@ -25,6 +25,7 @@
+ {{'CRONJOB.CREATE_EDIT.CLUSTER_MESSAGE' | translate}}
{{title | translate}}
+ {{'DAEMONSET.CREATE_EDIT.CLUSTER_MESSAGE' | translate}}
{{title}}
+ {{'DEPLOYMENT.CREATE_EDIT.CLUSTER_MESSAGE' | translate}}
{{title}}
+ {{'INGRESS.CREATE_EDIT.CLUSTER_MESSAGE' | translate}}
{{'PVC.CREATE_TMP' | translate}}
+ {{'PVC.CREATE_EDIT.CLUSTER_MESSAGE' | translate}}
diff --git a/src/frontend/src/app/portal/secret/create-edit-secrettpl/create-edit-secrettpl.component.html b/src/frontend/src/app/portal/secret/create-edit-secrettpl/create-edit-secrettpl.component.html index fb0aa61c7..c3810baae 100644 --- a/src/frontend/src/app/portal/secret/create-edit-secrettpl/create-edit-secrettpl.component.html +++ b/src/frontend/src/app/portal/secret/create-edit-secrettpl/create-edit-secrettpl.component.html @@ -6,6 +6,7 @@

{{'SECRET.CREATE_TMP' | translate}}

+ {{'SECRET.CREATE_EDIT.CLUSTER_MESSAGE' | translate}}
diff --git a/src/frontend/src/app/portal/statefulset/create-edit-statefulset/create-edit-statefulset.component.html b/src/frontend/src/app/portal/statefulset/create-edit-statefulset/create-edit-statefulset.component.html index fc04bca7c..27340997b 100644 --- a/src/frontend/src/app/portal/statefulset/create-edit-statefulset/create-edit-statefulset.component.html +++ b/src/frontend/src/app/portal/statefulset/create-edit-statefulset/create-edit-statefulset.component.html @@ -28,6 +28,7 @@
+ {{'STATEFULSET.CREATE_EDIT.CLUSTER_MESSAGE' | translate}}
Date: Fri, 14 Dec 2018 14:13:47 +0800 Subject: [PATCH 17/22] docs: automatically generate changelog by github_changelog_generator --- CHANGELOG.md | 68 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fd2c74da..91e81943b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,24 +1,62 @@ +# Change Log -1.1.0 / 2018-12-07 -================== +## [v1.1.0](https://github.com/Qihoo360/wayne/tree/v1.1.0) (2018-12-07) +[Full Changelog](https://github.com/Qihoo360/wayne/compare/v1.0.1...v1.1.0) -- Feature: Adding internationalization features -- Feature: Add Ingress support -- Feature: User can edit description in app page -- Feature: Add kubernetes deployment migration -- Feature: OpenAPI add RESTART_DEPLOYMENT -- Fix: Cancel forced to uppercase parameter cluster #73 -- Fix: Add the missing encoding in Sign-In form #82 -- Fix: fix sidenav overflow style #85 +**Implemented enhancements:** -1.0.1 / 2018-11-22 -================== +- Fix go admin description [\#97](https://github.com/Qihoo360/wayne/pull/97) ([chinaboard](https://github.com/chinaboard)) +- Feature/format frontend code [\#90](https://github.com/Qihoo360/wayne/pull/90) ([wilhelmguo](https://github.com/wilhelmguo)) +- Feature/rename oauth2 qihoo to oauth2 [\#67](https://github.com/Qihoo360/wayne/pull/67) ([wilhelmguo](https://github.com/wilhelmguo)) +- Feature/default config optimization [\#59](https://github.com/Qihoo360/wayne/pull/59) ([wilhelmguo](https://github.com/wilhelmguo)) +- Feature/kubernetes example dependency resource adjust [\#53](https://github.com/Qihoo360/wayne/pull/53) ([wilhelmguo](https://github.com/wilhelmguo)) +- Fix notification model orm warning [\#52](https://github.com/Qihoo360/wayne/pull/52) ([chengyumeng](https://github.com/chengyumeng)) -- Fix the problem of creating a user verification in the background is not strict. -- Fix init namespace error -- Ace editor optimization +**Fixed bugs:** +- Background does not set up cluster resources online display problem [\#94](https://github.com/Qihoo360/wayne/issues/94) +- 后台删除的项目,在回收站无法恢复 [\#93](https://github.com/Qihoo360/wayne/issues/93) +- 集群name不是全部大写,调用开放api报错 [\#66](https://github.com/Qihoo360/wayne/issues/66) +- PVC详情的扩展看板功能无效,js错误 Uncaught TypeError: Cannot read property 'nativeElement' of undefined [\#43](https://github.com/Qihoo360/wayne/issues/43) +- 计划任务提交后报错,并无法再点开高级配置 [\#38](https://github.com/Qihoo360/wayne/issues/38) +- Fix modal size change bug [\#60](https://github.com/Qihoo360/wayne/pull/60) ([BennieMeng](https://github.com/BennieMeng)) +- Fix CronJob bug that opens advanced mode paste yaml error r… [\#58](https://github.com/Qihoo360/wayne/pull/58) ([wilhelmguo](https://github.com/wilhelmguo)) +**Merged pull requests:** +- add restart deployment API [\#108](https://github.com/Qihoo360/wayne/pull/108) ([chengyumeng](https://github.com/chengyumeng)) +- Feature/add kubernetes deployment migration [\#102](https://github.com/Qihoo360/wayne/pull/102) ([wilhelmguo](https://github.com/wilhelmguo)) +- Feature/translate [\#72](https://github.com/Qihoo360/wayne/pull/72) ([BennieMeng](https://github.com/BennieMeng)) +## [v1.0.1](https://github.com/Qihoo360/wayne/tree/v1.0.1) (2018-11-22) +[Full Changelog](https://github.com/Qihoo360/wayne/compare/v1.0.0...v1.0.1) +**Implemented enhancements:** + +- English version of README? [\#18](https://github.com/Qihoo360/wayne/issues/18) +- 未校验用户邮箱格式 [\#11](https://github.com/Qihoo360/wayne/issues/11) +- 资源单位的显示 [\#7](https://github.com/Qihoo360/wayne/issues/7) +- kubernetes install optimization [\#51](https://github.com/Qihoo360/wayne/pull/51) ([wilhelmguo](https://github.com/wilhelmguo)) +- Feature/update kubernetes install [\#47](https://github.com/Qihoo360/wayne/pull/47) ([wilhelmguo](https://github.com/wilhelmguo)) +- Fix the problem of creating a user verification in the background is not strict. [\#35](https://github.com/Qihoo360/wayne/pull/35) ([chengyumeng](https://github.com/chengyumeng)) +- Feature/ace switch error notify [\#34](https://github.com/Qihoo360/wayne/pull/34) ([BennieMeng](https://github.com/BennieMeng)) +- 添加创建部署资源单位,样式调整 [\#27](https://github.com/Qihoo360/wayne/pull/27) ([BennieMeng](https://github.com/BennieMeng)) + +**Fixed bugs:** + +- 上线次数统计 日期选择后格式不正确 [\#20](https://github.com/Qihoo360/wayne/issues/20) +- 在前台界面,选择“部门概览”,再选择“上线记录”会报错 [\#19](https://github.com/Qihoo360/wayne/issues/19) +- switch start\_time or end\_time to query online statistics, api/v1/publish/statistics报错400 [\#13](https://github.com/Qihoo360/wayne/issues/13) +- resource api/v1/kubernetes/namespaces 报错500 [\#10](https://github.com/Qihoo360/wayne/issues/10) +- APIKeys 报错403 [\#9](https://github.com/Qihoo360/wayne/issues/9) +- 创建namespace,按钮无法点击 [\#4](https://github.com/Qihoo360/wayne/issues/4) +- Fix the problem that the first startup does not have namespace, causing the front desk to report an error. [\#44](https://github.com/Qihoo360/wayne/pull/44) ([chengyumeng](https://github.com/chengyumeng)) +- Fix load apikeys error when not set APIKey [\#33](https://github.com/Qihoo360/wayne/pull/33) ([wilhelmguo](https://github.com/wilhelmguo)) +- Fix edit namespace error bug [\#28](https://github.com/Qihoo360/wayne/pull/28) ([wilhelmguo](https://github.com/wilhelmguo)) +- Fix admin reportform dateformat error [\#26](https://github.com/Qihoo360/wayne/pull/26) ([wilhelmguo](https://github.com/wilhelmguo)) +- Fix init namespace error [\#6](https://github.com/Qihoo360/wayne/pull/6) ([wilhelmguo](https://github.com/wilhelmguo)) + +## [v1.0.0](https://github.com/Qihoo360/wayne/tree/v1.0.0) (2018-11-19) + + +\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* \ No newline at end of file From 773bbbfde7891fa79b01389e7e629b08d52ccf0d Mon Sep 17 00:00:00 2001 From: wilhelmguo Date: Fri, 14 Dec 2018 14:14:32 +0800 Subject: [PATCH 18/22] frontend: Fix Ordinary users cannot see Ingress resources --- src/frontend/src/app/shared/model/v1/permission.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/frontend/src/app/shared/model/v1/permission.ts b/src/frontend/src/app/shared/model/v1/permission.ts index 7a64b1abc..9b2fde717 100644 --- a/src/frontend/src/app/shared/model/v1/permission.ts +++ b/src/frontend/src/app/shared/model/v1/permission.ts @@ -30,6 +30,7 @@ export class TypePermission { this.deployment = input.deployment ? input.deployment : this.deployment; this.secret = input.secret ? input.secret : this.secret; this.service = input.service ? input.service : this.service; + this.ingress = input.ingress ? input.ingress : this.ingress; this.pvc = input.pvc ? input.pvc : this.pvc; this.configmap = input.configmap ? input.configmap : this.configmap; this.cronjob = input.cronjob ? input.cronjob : this.cronjob; From 42abd8ddae033e8897096b1d080e4d79ffc70f29 Mon Sep 17 00:00:00 2001 From: BennieMeng Date: Fri, 14 Dec 2018 14:58:01 +0800 Subject: [PATCH 19/22] frontend: add ignore rule of i18n format --- src/frontend/lang.js | 7 +++++++ src/frontend/src/assets/i18n/zh-Hans.json | 4 ++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/frontend/lang.js b/src/frontend/lang.js index a264aaf01..16d70c17d 100644 --- a/src/frontend/lang.js +++ b/src/frontend/lang.js @@ -43,9 +43,16 @@ if (process.argv[2] === 'format') { } if (process.argv[3] === 'zh-Hans') { const filePath = path.resolve(__dirname, 'src/assets/i18n', 'zh-Hans.json'); + const enSet = new Set(['CPU']); const result = JSON.stringify(defaultValue, null, 2).replace(/([\u4e00-\u9fa5]+)([a-zA-Z]+)/g, function (match, $1, $2) { + if (enSet.has($2)) { + return match + } return $1 + ' ' + $2; }).replace(/([a-zA-Z]+)([\u4e00-\u9fa5]+)/g, function (match, $1, $2) { + if (enSet.has($1)) { + return match; + } return $1 + ' ' + $2; }); fs.writeFile(filePath, result, err => { diff --git a/src/frontend/src/assets/i18n/zh-Hans.json b/src/frontend/src/assets/i18n/zh-Hans.json index 8dcd7f8f2..d0381f8b6 100644 --- a/src/frontend/src/assets/i18n/zh-Hans.json +++ b/src/frontend/src/assets/i18n/zh-Hans.json @@ -141,8 +141,8 @@ "CREATE_APP": "创建项目", "DEPARTMENT_NAME": "部门名称", "CREATE_TIME": "创建时间", - "CPU_USAGE": "CPU 使用(核)", - "CPU_USAGE_SHORT": "CPU 使用(核)", + "CPU_USAGE": "CPU使用(核)", + "CPU_USAGE_SHORT": "CPU使用(核)", "MEMORY_USAGE": "内存使用(G)", "MEMORY_USAGE_SHORT": "内存使用(G)", "DEPLOY_FREQ": "部署上线频数", From 628fdcac6680906316fb3cd5375caf50cac7efea Mon Sep 17 00:00:00 2001 From: BennieMeng Date: Fri, 14 Dec 2018 15:09:18 +0800 Subject: [PATCH 20/22] frontend: add format --- src/frontend/lang.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/frontend/lang.js b/src/frontend/lang.js index 16d70c17d..f5c0e1326 100644 --- a/src/frontend/lang.js +++ b/src/frontend/lang.js @@ -43,14 +43,16 @@ if (process.argv[2] === 'format') { } if (process.argv[3] === 'zh-Hans') { const filePath = path.resolve(__dirname, 'src/assets/i18n', 'zh-Hans.json'); - const enSet = new Set(['CPU']); + const enSet = new Set([]); + const zhSet = new Set([]); + const matchSet = new Set(['CPU使用']); const result = JSON.stringify(defaultValue, null, 2).replace(/([\u4e00-\u9fa5]+)([a-zA-Z]+)/g, function (match, $1, $2) { - if (enSet.has($2)) { + if (matchSet.has(match) || zhSet.has($1) || enSet.has($2)) { return match } return $1 + ' ' + $2; }).replace(/([a-zA-Z]+)([\u4e00-\u9fa5]+)/g, function (match, $1, $2) { - if (enSet.has($1)) { + if (matchSet.has(match) || zhSet.has($2) || enSet.has($1)) { return match; } return $1 + ' ' + $2; From 6f377317e1099f72cb32ff8cd4380f9967a56c4d Mon Sep 17 00:00:00 2001 From: wilhelmguo Date: Fri, 14 Dec 2018 15:14:26 +0800 Subject: [PATCH 21/22] frontend: optimization admin nav display --- .../src/app/admin/nav/nav.component.html | 12 ++++++- .../src/app/admin/nav/nav.component.ts | 31 +++++++++++++++++-- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/frontend/src/app/admin/nav/nav.component.html b/src/frontend/src/app/admin/nav/nav.component.html index 833164919..ccc4853f1 100644 --- a/src/frontend/src/app/admin/nav/nav.component.html +++ b/src/frontend/src/app/admin/nav/nav.component.html @@ -9,7 +9,17 @@
- + + {{showLang(currentLang)}} + + + + {{showLang(lang)}} + + + + + {{authService.currentUser?.display}} diff --git a/src/frontend/src/app/admin/nav/nav.component.ts b/src/frontend/src/app/admin/nav/nav.component.ts index bae78455a..118c91aa0 100644 --- a/src/frontend/src/app/admin/nav/nav.component.ts +++ b/src/frontend/src/app/admin/nav/nav.component.ts @@ -3,6 +3,8 @@ import { AuthService } from '../../shared/auth/auth.service'; import { Router } from '@angular/router'; import { AuthoriseService } from '../../shared/client/v1/auth.service'; import { LoginTokenKey } from '../../shared/shared.const'; +import { LangChangeEvent, TranslateService } from '@ngx-translate/core'; +import { StorageService } from '../../shared/client/v1/storage.service'; @Component({ selector: 'wayne-nav', @@ -10,17 +12,42 @@ import { LoginTokenKey } from '../../shared/shared.const'; styleUrls: ['./nav.component.scss'] }) export class NavComponent implements OnInit { + currentLang: string; constructor(public authService: AuthService, private authoriseService: AuthoriseService, + public translate: TranslateService, + private storage: StorageService, private router: Router) { } ngOnInit() { + this.currentLang = this.translate.currentLang; + this.translate.onLangChange.subscribe((event: LangChangeEvent) => { + this.currentLang = event.lang; + }); } goFront() { - if (window) window.location.href = '/'; + if (window) { + window.location.href = '/'; + } + } + + showLang(lang: string): string { + switch (lang) { + case 'en': + return 'English'; + case 'zh-Hans': + return '中文简体'; + default: + return ''; + } + } + + changeLang(lang: string) { + this.translate.use(lang); + this.storage.save('lang', lang); } logout() { @@ -29,7 +56,7 @@ export class NavComponent implements OnInit { } getTitle() { - let imagePrefix = this.authService.config['system.title']; + const imagePrefix = this.authService.config['system.title']; return imagePrefix ? imagePrefix : 'Wayne'; } From 302131f4f3dfec8f4959e4948320df77923a6b5d Mon Sep 17 00:00:00 2001 From: BennieMeng Date: Fri, 14 Dec 2018 07:48:24 +0000 Subject: [PATCH 22/22] frontend: update zh-Hans.json --- src/frontend/src/assets/i18n/zh-Hans.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/frontend/src/assets/i18n/zh-Hans.json b/src/frontend/src/assets/i18n/zh-Hans.json index d0381f8b6..cb4898b34 100644 --- a/src/frontend/src/assets/i18n/zh-Hans.json +++ b/src/frontend/src/assets/i18n/zh-Hans.json @@ -351,7 +351,7 @@ "EDIT": "编辑状态副本集", "DELETE": "删除状态副本集", "CREATE_EDIT": { - "CLUSTER_MESSAGE": "需要先在后台配置 Namespace 可用集群才可以创建部署" + "CLUSTER_MESSAGE": "需要先在后台配置 Namespace 可用集群才可以创建状态副本集" } }, "DAEMONSET": { @@ -360,7 +360,7 @@ "EDIT": "编辑守护进程集", "DELETE": "删除守护进程集", "CREATE_EDIT": { - "CLUSTER_MESSAGE": "需要先在后台配置 Namespace 可用集群才可以创建部署" + "CLUSTER_MESSAGE": "需要先在后台配置 Namespace 可用集群才可以创建守护进程集" } }, "CRONJOB": { @@ -369,7 +369,7 @@ "EDIT": "编辑计划任务", "DELETE": "删除计划任务", "CREATE_EDIT": { - "CLUSTER_MESSAGE": "需要先在后台配置 Namespace 可用集群才可以创建部署" + "CLUSTER_MESSAGE": "需要先在后台配置 Namespace 可用集群才可以创建计划任务" }, "LIST": "计划任务列表", "DELETE_LIST": "已删除计划任务列表", @@ -391,7 +391,7 @@ }, "INGRESS": { "CREATE_EDIT": { - "CLUSTER_MESSAGE": "需要先在后台配置 Namespace 可用集群才可以创建部署" + "CLUSTER_MESSAGE": "需要先在后台配置 Namespace 可用集群才可以创建 Ingress" } }, "CONFIGMAP": { @@ -400,7 +400,7 @@ "EDIT": "编辑配置集", "DELETE": "删除配置集", "CREATE_EDIT_TMP": { - "CLUSTER_MESSAGE": "需要先在后台配置 Namespace 可用集群才可以创建部署" + "CLUSTER_MESSAGE": "需要先在后台配置 Namespace 可用集群才可以创建配置集" } }, "SECRET": { @@ -409,7 +409,7 @@ "EDIT": "编辑加密字典", "DELETE": "删除加密字典", "CREATE_EDIT_TMP": { - "CLUSTER_MESSAGE": "需要先在后台配置 Namespace 可用集群才可以创建部署" + "CLUSTER_MESSAGE": "需要先在后台配置 Namespace 可用集群才可以创建加密字典" } }, "PVC": { @@ -439,7 +439,7 @@ "ROLLBACK_SNAPSHOOT": "回滚快照", "RECORD": "共{{value}}条快照记录", "CREATE_EDIT_TMP": { - "CLUSTER_MESSAGE": "需要先在后台配置 Namespace 可用集群才可以创建部署" + "CLUSTER_MESSAGE": "需要先在后台配置 Namespace 可用集群才可以创建 PVC" } }, "WEBHOOK": { @@ -451,4 +451,4 @@ }, "OTHER": "其他", "OF": "的" -} \ No newline at end of file +}