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:
wyike
2022-01-14 10:16:31 +08:00
committed by GitHub
parent 8b5d7ed395
commit f39a3fb792
6 changed files with 414 additions and 0 deletions
+47
View File
@@ -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
}
+17
View File
@@ -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"`
}
+93
View File
@@ -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))
}
+138
View File
@@ -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))
})
})