mirror of
https://github.com/kubevela/kubevela.git
synced 2026-08-19 04:26:39 +00:00
Feat: system information collection logic in apiserver (#3082)
* Feat: userInfoCollection Signed-off-by: wangyike <wangyike_wyk@163.com> * Signed-off-by: wangyike <wangyike_wyk@163.com> change enable/disable to update interface Signed-off-by: wangyike <wangyike_wyk@163.com>
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
Copyright 2021 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package model
|
||||
|
||||
func init() {
|
||||
RegistModel(&SystemInfo{})
|
||||
}
|
||||
|
||||
// SystemInfo systemInfo model
|
||||
type SystemInfo struct {
|
||||
BaseModel
|
||||
InstallID string `json:"installID"`
|
||||
EnableCollection bool `json:"enableCollection"`
|
||||
}
|
||||
|
||||
// TableName return custom table name
|
||||
func (u *SystemInfo) TableName() string {
|
||||
return tableNamePrefix + "system_info"
|
||||
}
|
||||
|
||||
// PrimaryKey return custom primary key
|
||||
func (u *SystemInfo) PrimaryKey() string {
|
||||
return u.InstallID
|
||||
}
|
||||
|
||||
// Index return custom index
|
||||
func (u *SystemInfo) Index() map[string]string {
|
||||
index := make(map[string]string)
|
||||
if u.InstallID != "" {
|
||||
index["installID"] = u.InstallID
|
||||
}
|
||||
return index
|
||||
}
|
||||
@@ -987,3 +987,20 @@ type ListRevisionsResponse struct {
|
||||
type DetailRevisionResponse struct {
|
||||
model.ApplicationRevision
|
||||
}
|
||||
|
||||
// SystemInfoResponse get SystemInfo
|
||||
type SystemInfoResponse struct {
|
||||
model.SystemInfo
|
||||
SystemVersion SystemVersion
|
||||
}
|
||||
|
||||
// SystemInfoRequest request by update SystemInfo
|
||||
type SystemInfoRequest struct {
|
||||
EnableCollection bool
|
||||
}
|
||||
|
||||
// SystemVersion contains KubeVela version
|
||||
type SystemVersion struct {
|
||||
KubeVelaVersion string `json:"KubeVelaVersion"`
|
||||
GitVersion string `json:"gitVersion"`
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
Copyright 2021 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package usecase
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/oam-dev/kubevela/version"
|
||||
|
||||
v1 "github.com/oam-dev/kubevela/pkg/apiserver/rest/apis/v1"
|
||||
|
||||
"k8s.io/apimachinery/pkg/util/rand"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/model"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/datastore"
|
||||
)
|
||||
|
||||
// SystemInfoUsecase is usecase for systemInfoCollection
|
||||
type SystemInfoUsecase interface {
|
||||
GetSystemInfo(ctx context.Context) (*v1.SystemInfoResponse, error)
|
||||
DeleteSystemInfo(ctx context.Context) error
|
||||
UpdateSystemInfo(ctx context.Context, sysInfo v1.SystemInfoRequest) (*v1.SystemInfoResponse, error)
|
||||
}
|
||||
|
||||
type systemInfoUsecaseImpl struct {
|
||||
ds datastore.DataStore
|
||||
}
|
||||
|
||||
// NewSystemInfoUsecase return a systemInfoCollectionUsecase
|
||||
func NewSystemInfoUsecase(ds datastore.DataStore) SystemInfoUsecase {
|
||||
return &systemInfoUsecaseImpl{ds: ds}
|
||||
}
|
||||
|
||||
func (u systemInfoUsecaseImpl) GetSystemInfo(ctx context.Context) (*v1.SystemInfoResponse, error) {
|
||||
// first get request will init systemInfoCollection{installId: {random}, enableCollection: true}
|
||||
info := &model.SystemInfo{}
|
||||
entities, err := u.ds.List(ctx, info, &datastore.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(entities) != 0 {
|
||||
info := entities[0].(*model.SystemInfo)
|
||||
return &v1.SystemInfoResponse{SystemInfo: *info, SystemVersion: v1.SystemVersion{KubeVelaVersion: version.VelaVersion, GitVersion: version.GitRevision}}, nil
|
||||
}
|
||||
installID := rand.String(16)
|
||||
info.InstallID = installID
|
||||
info.EnableCollection = true
|
||||
err = u.ds.Add(ctx, info)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v1.SystemInfoResponse{SystemInfo: *info, SystemVersion: v1.SystemVersion{KubeVelaVersion: version.VelaVersion, GitVersion: version.GitRevision}}, nil
|
||||
}
|
||||
|
||||
func (u systemInfoUsecaseImpl) UpdateSystemInfo(ctx context.Context, sysInfo v1.SystemInfoRequest) (*v1.SystemInfoResponse, error) {
|
||||
info, err := u.GetSystemInfo(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
modifiedInfo := model.SystemInfo{InstallID: info.InstallID, EnableCollection: sysInfo.EnableCollection}
|
||||
err = u.ds.Put(ctx, &modifiedInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &v1.SystemInfoResponse{SystemInfo: modifiedInfo, SystemVersion: v1.SystemVersion{KubeVelaVersion: version.VelaVersion, GitVersion: version.GitRevision}}, nil
|
||||
}
|
||||
|
||||
func (u systemInfoUsecaseImpl) DeleteSystemInfo(ctx context.Context) error {
|
||||
info, err := u.GetSystemInfo(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = u.ds.Delete(ctx, info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
Copyright 2021 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package webservice
|
||||
|
||||
import (
|
||||
restfulspec "github.com/emicklei/go-restful-openapi/v2"
|
||||
"github.com/emicklei/go-restful/v3"
|
||||
|
||||
apis "github.com/oam-dev/kubevela/pkg/apiserver/rest/apis/v1"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/rest/usecase"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/rest/utils/bcode"
|
||||
)
|
||||
|
||||
type systemInfoWebService struct {
|
||||
useCase usecase.SystemInfoUsecase
|
||||
}
|
||||
|
||||
// NewSystemInfoWebService return systemInfo webservice
|
||||
func NewSystemInfoWebService(systemInfoUseCase usecase.SystemInfoUsecase) WebService {
|
||||
return &systemInfoWebService{useCase: systemInfoUseCase}
|
||||
}
|
||||
|
||||
// GetWebService return systemInfo webservice
|
||||
func (u systemInfoWebService) GetWebService() *restful.WebService {
|
||||
ws := new(restful.WebService)
|
||||
ws.Path(versionPrefix+"/system_info").Consumes(restful.MIME_XML, restful.MIME_JSON).
|
||||
Produces(restful.MIME_JSON, restful.MIME_XML).
|
||||
Doc("api for systemInfo management")
|
||||
|
||||
tags := []string{"systemInfo"}
|
||||
|
||||
// Get
|
||||
ws.Route(ws.GET("/").To(u.getSystemInfo).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Returns(200, "", apis.SystemInfoResponse{}).
|
||||
Returns(400, "", bcode.Bcode{}).
|
||||
Writes(apis.SystemInfoResponse{}))
|
||||
|
||||
// Delete
|
||||
ws.Route(ws.DELETE("/").To(u.deleteSystemInfo).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Returns(200, "", apis.SystemInfoResponse{}).
|
||||
Returns(400, "", bcode.Bcode{}).
|
||||
Writes(apis.SystemInfoResponse{}))
|
||||
|
||||
// Post
|
||||
ws.Route(ws.PUT("/").To(u.updateSystemInfo).
|
||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||
Reads(apis.SystemInfoRequest{}).
|
||||
Returns(200, "", apis.SystemInfoResponse{}).
|
||||
Returns(400, "", bcode.Bcode{}).
|
||||
Writes(apis.SystemInfoResponse{}))
|
||||
|
||||
return ws
|
||||
}
|
||||
|
||||
func (u systemInfoWebService) getSystemInfo(req *restful.Request, res *restful.Response) {
|
||||
info, err := u.useCase.GetSystemInfo(req.Request.Context())
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
if err := res.WriteEntity(info); err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (u systemInfoWebService) updateSystemInfo(req *restful.Request, res *restful.Response) {
|
||||
var systemInfoReq apis.SystemInfoRequest
|
||||
var args []byte
|
||||
_, err := req.Request.Body.Read(args)
|
||||
if err == nil {
|
||||
err := req.ReadEntity(&systemInfoReq)
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
if err = validate.Struct(&systemInfoReq); err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
info, err := u.useCase.UpdateSystemInfo(req.Request.Context(), systemInfoReq)
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
if err := res.WriteEntity(info); err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (u systemInfoWebService) deleteSystemInfo(req *restful.Request, res *restful.Response) {
|
||||
err := u.useCase.DeleteSystemInfo(req.Request.Context())
|
||||
if err != nil {
|
||||
bcode.ReturnError(req, res, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -71,6 +71,7 @@ func Init(ds datastore.DataStore, addonCacheTime time.Duration) {
|
||||
envBindingUsecase := usecase.NewEnvBindingUsecase(ds, workflowUsecase, definitionUsecase, envUsecase)
|
||||
applicationUsecase := usecase.NewApplicationUsecase(ds, workflowUsecase, envBindingUsecase, envUsecase, targetUsecase, definitionUsecase, projectUsecase)
|
||||
webhookUsecase := usecase.NewWebhookUsecase(ds, applicationUsecase)
|
||||
systemInfoUsecase := usecase.NewSystemInfoUsecase(ds)
|
||||
|
||||
// init for default values
|
||||
|
||||
@@ -93,4 +94,6 @@ func Init(ds datastore.DataStore, addonCacheTime time.Duration) {
|
||||
RegisterWebService(NewTargetWebService(targetUsecase, applicationUsecase))
|
||||
RegisterWebService(NewVelaQLWebService(velaQLUsecase))
|
||||
RegisterWebService(NewWebhookWebService(webhookUsecase, applicationUsecase))
|
||||
|
||||
RegisterWebService(NewSystemInfoWebService(systemInfoUsecase))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
Copyright 2021 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package e2e_apiserver_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
apisv1 "github.com/oam-dev/kubevela/pkg/apiserver/rest/apis/v1"
|
||||
)
|
||||
|
||||
func put(path string, body interface{}) *http.Response {
|
||||
b, err := json.Marshal(body)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
req, err := http.NewRequest(http.MethodPut, baseURL+path, bytes.NewBuffer(b))
|
||||
Expect(err).Should(BeNil())
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(res).ShouldNot(BeNil())
|
||||
Expect(res.StatusCode).Should(Equal(200))
|
||||
return res
|
||||
}
|
||||
|
||||
var _ = Describe("Test system info rest api", func() {
|
||||
BeforeEach(func() {
|
||||
req, err := http.NewRequest(http.MethodDelete, baseURL+"/api/v1/system_info/", nil)
|
||||
Expect(err).Should(BeNil())
|
||||
deleteRes, err := http.DefaultClient.Do(req)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(deleteRes).ShouldNot(BeNil())
|
||||
Expect(deleteRes.StatusCode).Should(Equal(200))
|
||||
})
|
||||
|
||||
It("Test get SystemInfo", func() {
|
||||
response := get("/api/v1/system_info/")
|
||||
Expect(response).ShouldNot(BeNil())
|
||||
Expect(response.Body).ShouldNot(BeNil())
|
||||
Expect(response.StatusCode).Should(Equal(200))
|
||||
|
||||
defer response.Body.Close()
|
||||
|
||||
var info apisv1.SystemInfoResponse
|
||||
err := json.NewDecoder(response.Body).Decode(&info)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(len(info.InstallID)).ShouldNot(BeEquivalentTo(0))
|
||||
Expect(info.EnableCollection).Should(BeEquivalentTo(true))
|
||||
systemID := info.InstallID
|
||||
|
||||
// check several times the systemID should not change
|
||||
for i := 0; i < 5; i++ {
|
||||
check := get("/api/v1/system_info/")
|
||||
Expect(check).ShouldNot(BeNil())
|
||||
Expect(check.Body).ShouldNot(BeNil())
|
||||
Expect(check.StatusCode).Should(Equal(200))
|
||||
|
||||
var checkInfo apisv1.SystemInfoResponse
|
||||
err := json.NewDecoder(check.Body).Decode(&checkInfo)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(checkInfo.InstallID).Should(BeEquivalentTo(systemID))
|
||||
}
|
||||
})
|
||||
|
||||
It("Test disable/enable systemInfoCollection", func() {
|
||||
response := get("/api/v1/system_info/")
|
||||
Expect(response).ShouldNot(BeNil())
|
||||
Expect(response.Body).ShouldNot(BeNil())
|
||||
Expect(response.StatusCode).Should(Equal(200))
|
||||
|
||||
defer response.Body.Close()
|
||||
|
||||
var info apisv1.SystemInfoResponse
|
||||
err := json.NewDecoder(response.Body).Decode(&info)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(len(info.InstallID)).ShouldNot(BeEquivalentTo(0))
|
||||
Expect(info.EnableCollection).Should(BeEquivalentTo(true))
|
||||
installID := info.InstallID
|
||||
|
||||
response = put("/api/v1/system_info/", apisv1.SystemInfoRequest{EnableCollection: false})
|
||||
info = apisv1.SystemInfoResponse{}
|
||||
err = json.NewDecoder(response.Body).Decode(&info)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(len(info.InstallID)).ShouldNot(BeEquivalentTo(0))
|
||||
Expect(info.EnableCollection).Should(BeEquivalentTo(false))
|
||||
|
||||
getRes := get("/api/v1/system_info/")
|
||||
Expect(getRes).ShouldNot(BeNil())
|
||||
Expect(getRes.Body).ShouldNot(BeNil())
|
||||
Expect(getRes.StatusCode).Should(Equal(200))
|
||||
|
||||
var checkInfo apisv1.SystemInfoResponse
|
||||
err = json.NewDecoder(getRes.Body).Decode(&checkInfo)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(checkInfo.InstallID).Should(BeEquivalentTo(installID))
|
||||
Expect(checkInfo.EnableCollection).Should(BeEquivalentTo(false))
|
||||
|
||||
response = put("/api/v1/system_info/", apisv1.SystemInfoRequest{EnableCollection: true})
|
||||
Expect(response).ShouldNot(BeNil())
|
||||
Expect(response.StatusCode).Should(Equal(200))
|
||||
|
||||
var enableInfo apisv1.SystemInfoResponse
|
||||
err = json.NewDecoder(response.Body).Decode(&enableInfo)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(len(enableInfo.InstallID)).ShouldNot(BeEquivalentTo(0))
|
||||
Expect(enableInfo.EnableCollection).Should(BeEquivalentTo(true))
|
||||
Expect(enableInfo.InstallID).Should(BeEquivalentTo(installID))
|
||||
|
||||
getAgainRes := get("/api/v1/system_info/")
|
||||
Expect(getRes).ShouldNot(BeNil())
|
||||
Expect(getRes.Body).ShouldNot(BeNil())
|
||||
Expect(getRes.StatusCode).Should(Equal(200))
|
||||
|
||||
var checkAgainInfo apisv1.SystemInfoResponse
|
||||
err = json.NewDecoder(getAgainRes.Body).Decode(&checkAgainInfo)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(checkAgainInfo.InstallID).Should(BeEquivalentTo(installID))
|
||||
Expect(checkAgainInfo.EnableCollection).Should(BeEquivalentTo(true))
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user