diff --git a/service/database/config/config.yml b/service/database/config/config.yml deleted file mode 100644 index 4683ee496c5..00000000000 --- a/service/database/config/config.yml +++ /dev/null @@ -1,2 +0,0 @@ -server: - addr: ":9090" \ No newline at end of file diff --git a/service/database/deploy/manifests/deploy.yaml b/service/database/deploy/manifests/deploy.yaml index 4e9b0032668..22c56966c07 100644 --- a/service/database/deploy/manifests/deploy.yaml +++ b/service/database/deploy/manifests/deploy.yaml @@ -37,7 +37,6 @@ spec: env: - name: PROMETHEUS_SERVICE_HOST value: http://kb-addon-prometheus-server.kb-system.svc.cluster.local - - name: OBJECT_STORAGE_INSTANCE image: ghcr.io/labring/sealos-database-service:latest imagePullPolicy: Always name: database-monitor @@ -45,9 +44,12 @@ spec: - containerPort: 9090 protocol: TCP resources: + limits: + cpu: 500m + memory: 1024Mi requests: - cpu: 1m - memory: 500M + cpu: 5m + memory: 64Mi securityContext: allowPrivilegeEscalation: false capabilities: diff --git a/service/database/main.go b/service/database/main.go index 73cc8b5ba26..e6183a1d740 100644 --- a/service/database/main.go +++ b/service/database/main.go @@ -4,53 +4,20 @@ import ( "flag" "fmt" "log" - "net" - "net/http" "os" - "github.com/labring/sealos/service/database/server" + dbserver "github.com/labring/sealos/service/database/server" + "github.com/labring/sealos/service/pkg/server" ) -type RestartableServer struct { - configFile string - // server *server.PromServer - // hs *http.Server -} - -func (rs *RestartableServer) Serve(c *server.Config) { - var ps, err = server.NewPromServer(c) - if err != nil { - fmt.Printf("Failed to create auth server: %s\n", err) - return - } - - hs := &http.Server{ - Addr: c.Server.ListenAddress, - Handler: ps, - } - - var listener net.Listener - listener, err = net.Listen("tcp", c.Server.ListenAddress) - if err != nil { - fmt.Println(err) - return - } - fmt.Printf("Serve on %s\n", c.Server.ListenAddress) - - if err := hs.Serve(listener); err != nil { - fmt.Println(err) - return - } -} - func main() { - log.SetOutput(os.Stdout) // 将日志输出定向到标准输出(stdout) + log.SetOutput(os.Stdout) log.SetFlags(log.LstdFlags | log.Lshortfile) flag.Parse() cf := flag.Arg(0) if cf == "" { - fmt.Println("Config file not sepcified") + fmt.Println("The config file is not specified") return } @@ -59,8 +26,10 @@ func main() { fmt.Println(err) return } - rs := RestartableServer{ - configFile: cf, + + rs := dbserver.DatabaseServer{ + ConfigFile: cf, } + rs.Serve(config) } diff --git a/service/database/server/server.go b/service/database/server/server.go index f3d7cdc6253..bba3155633a 100644 --- a/service/database/server/server.go +++ b/service/database/server/server.go @@ -1,202 +1,38 @@ package server import ( - "encoding/json" "fmt" - "log" + "net" "net/http" - "net/url" - "text/template" - "github.com/labring/sealos/service/pkg/auth" - - "github.com/labring/sealos/service/database/api" - "github.com/labring/sealos/service/database/request" + "github.com/labring/sealos/service/pkg/server" ) -type PromServer struct { - Config *Config -} - -func NewPromServer(c *Config) (*PromServer, error) { - ps := &PromServer{ - Config: c, - } - return ps, nil -} - -func (ps *PromServer) Authenticate(pr *api.PromRequest) error { - return auth.Authenticate(pr.NS, pr.Pwd) -} - -func (ps *PromServer) Request(pr *api.PromRequest) (*api.QueryResult, error) { - body, err := request.PrometheusPre(pr) - if err != nil { - return nil, err - } - var result *api.QueryResult - if err := json.Unmarshal(body, &result); err != nil { - return nil, err - } - return result, err -} - -func (ps *PromServer) DBReq(pr *api.PromRequest) (*api.QueryResult, error) { - body, err := request.PrometheusNew(pr) - if err != nil { - return nil, err - } - var result *api.QueryResult - if err := json.Unmarshal(body, &result); err != nil { - return nil, err - } - return result, nil -} - -func (ps *PromServer) ParseRequest(req *http.Request) (*api.PromRequest, error) { - pr := &api.PromRequest{} - - auth := req.Header.Get("Authorization") - - if pwd, err := url.PathUnescape(auth); err == nil { - pr.Pwd = pwd - } else { - return nil, err - } - if pr.Pwd == "" { - return nil, api.ErrEmptyKubeconfig - } - - if err := req.ParseForm(); err != nil { - return nil, err - } - - for key, val := range req.Form { - switch key { - case "query": - pr.Query = val[0] - case "step": - pr.Range.Step = val[0] - case "start": - pr.Range.Start = val[0] - case "end": - pr.Range.End = val[0] - case "time": - pr.Range.Time = val[0] - case "namespace": - pr.NS = val[0] - case "type": - pr.Type = val[0] - case "app": - pr.Cluster = val[0] - } - } - - if pr.NS == "" || pr.Query == "" { - return nil, api.ErrUncompleteParam - } - - return pr, nil -} - -// 获取客户端请求的信息 -func (ps *PromServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) { - pathPrefix := "" - switch { - case req.URL.Path == pathPrefix+"/query": // 将废弃 - ps.doReqPre(rw, req) - case req.URL.Path == pathPrefix+"/q": - ps.doReqNew(rw, req) - default: - http.Error(rw, "Not found", http.StatusNotFound) - return - } -} - -func (ps *PromServer) doReqNew(rw http.ResponseWriter, req *http.Request) { - pr, err := ps.ParseRequest(req) - if err != nil { - http.Error(rw, fmt.Sprintf("Bad request (%s)", err), http.StatusBadRequest) - log.Printf("Bad request (%s)\n", err) - return - } - - if err := ps.Authenticate(pr); err != nil { - http.Error(rw, fmt.Sprintf("Authentication failed (%s)", err), http.StatusInternalServerError) - log.Printf("Authentication failed (%s)\n", err) - return - } - - res, err := ps.DBReq(pr) - if err != nil { - http.Error(rw, fmt.Sprintf("Query failed (%s)", err), http.StatusInternalServerError) - log.Printf("Query failed (%s)\n", err) - return - } - - result, err := json.Marshal(res) - if err != nil { - http.Error(rw, "Result failed (invalid query expression)", http.StatusInternalServerError) - log.Printf("Reulst failed (%s)\n", err) - return - } - - rw.Header().Set("Content-Type", "application/json") - - tmpl := template.New("responseTemplate").Delims("{{", "}}") - tmpl, err = tmpl.Parse(`{{.}}`) - if err != nil { - log.Printf("template failed: %s\n", err) - http.Error(rw, "Internal Server Error", http.StatusInternalServerError) - return - } - if err = tmpl.Execute(rw, string(result)); err != nil { - log.Printf("Reulst failed: %s\n", err) - http.Error(rw, "Internal Server Error", http.StatusInternalServerError) - return - } +type DatabaseServer struct { + ConfigFile string } -func (ps *PromServer) doReqPre(rw http.ResponseWriter, req *http.Request) { - pr, err := ps.ParseRequest(req) +func (rs *DatabaseServer) Serve(c *server.Config) { + ps, err := server.NewPromServer(c) if err != nil { - http.Error(rw, fmt.Sprintf("Bad request (%s)", err), http.StatusBadRequest) - log.Printf("Bad request (%s)\n", err) + fmt.Printf("Failed to create auth server: %s\n", err) return } - if err := ps.Authenticate(pr); err != nil { - http.Error(rw, fmt.Sprintf("Authentication failed (%s)", err), http.StatusInternalServerError) - log.Printf("Authentication failed (%s)\n", err) - log.Printf("Kubeconfig (%s)\n", pr.Pwd) + hs := &http.Server{ + Addr: c.Server.ListenAddress, + Handler: ps, } - res, err := ps.Request(pr) + listener, err := net.Listen("tcp", c.Server.ListenAddress) if err != nil { - http.Error(rw, fmt.Sprintf("Query failed (%s)", err), http.StatusInternalServerError) - log.Printf("Query failed (%s)\n", err) + fmt.Println(err) return } + fmt.Printf("Serve on %s\n", c.Server.ListenAddress) - result, err := json.Marshal(res) - if err != nil { - http.Error(rw, "Result failed (invalid query expression)", http.StatusInternalServerError) - log.Printf("Reulst failed (%s)\n", err) - return - } - - rw.Header().Set("Content-Type", "application/json") - - tmpl := template.New("responseTemplate").Delims("{{", "}}") - tmpl, err = tmpl.Parse(`{{.}}`) - if err != nil { - log.Printf("template failed: %s\n", err) - http.Error(rw, "Internal Server Error", http.StatusInternalServerError) - return - } - if err = tmpl.Execute(rw, string(result)); err != nil { - log.Printf("Reulst failed: %s\n", err) - http.Error(rw, "Internal Server Error", http.StatusInternalServerError) + if err := hs.Serve(listener); err != nil { + fmt.Println(err) return } } diff --git a/service/minio/Dockerfile b/service/minio/Dockerfile new file mode 100644 index 00000000000..565b0de418b --- /dev/null +++ b/service/minio/Dockerfile @@ -0,0 +1,9 @@ +# FROM scratch +FROM gcr.io/distroless/static:nonroot +# FROM gengweifeng/gcr-io-distroless-static-nonroot +ARG TARGETARCH +COPY bin/service-minio-$TARGETARCH /manager +EXPOSE 9090 +USER 65532:65532 + +ENTRYPOINT ["/manager"] \ No newline at end of file diff --git a/service/minio/Makefile b/service/minio/Makefile new file mode 100644 index 00000000000..0fb3c95d844 --- /dev/null +++ b/service/minio/Makefile @@ -0,0 +1,55 @@ +IMG ?= ghcr.io/labring/sealos-minio-service:latest + +# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set) +ifeq (,$(shell go env GOBIN)) +GOBIN=$(shell go env GOPATH)/bin +else +GOBIN=$(shell go env GOBIN) +endif + +# only support linux, non cgo +PLATFORMS ?= linux_arm64 linux_amd64 +GOOS=linux +CGO_ENABLED=0 +GOARCH=$(shell go env GOARCH) + +GO_BUILD_FLAGS=-trimpath -ldflags "-s -w" + +.PHONY: all +all: build + +##@ General + +# The help target prints out all targets with their descriptions organized +# beneath their categories. The categories are represented by '##@' and the +# target descriptions by '##'. The awk commands is responsible for reading the +# entire set of makefiles included in this invocation, looking for lines of the +# file as xyz: ## something, and then pretty-format the target and help. Then, +# if there's a line with ##@ something, that gets pretty-printed as a category. +# More info on the usage of ANSI control characters for terminal formatting: +# https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters +# More info on the awk command: +# http://linuxcommand.org/lc3_adv_awk.php + +.PHONY: help +help: ## Display this help. + @awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) + +##@ Build + +.PHONY: clean +clean: + rm -f $(SERVICE_NAME) + +.PHONY: build +build: clean ## Build service-hub binary. + CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GOOS) go build $(GO_BUILD_FLAGS) -o bin/manager main.go + +.PHONY: docker-build +docker-build: build + mv bin/manager bin/service-minio-${TARGETARCH} + docker build -t $(IMG) . + +.PHONY: docker-push +docker-push: + docker push $(IMG) diff --git a/service/minio/deploy/Kubefile b/service/minio/deploy/Kubefile new file mode 100644 index 00000000000..035ec02f5a0 --- /dev/null +++ b/service/minio/deploy/Kubefile @@ -0,0 +1,5 @@ +FROM scratch +COPY registry registry +COPY manifests manifests + +CMD ["kubectl apply -f manifests/deploy.yaml"] \ No newline at end of file diff --git a/service/minio/deploy/manifests/deploy.yaml b/service/minio/deploy/manifests/deploy.yaml new file mode 100644 index 00000000000..ee6c656c288 --- /dev/null +++ b/service/minio/deploy/manifests/deploy.yaml @@ -0,0 +1,88 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + labels: + app: object-storage-monitor + name: object-storage-monitor-config + namespace: objectstorage-system +data: + config.yml: | + server: + addr: ":9090" +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app: object-storage-monitor + name: object-storage-monitor + namespace: sealos +spec: + replicas: 1 + selector: + matchLabels: + app: object-storage-monitor + strategy: + type: Recreate + template: + metadata: + labels: + app: object-storage-monitor + spec: + containers: + - args: + - /config/config.yml + command: + - /manager + env: + - name: PROMETHEUS_SERVICE_HOST + value: http://prometheus-object-storage.objectstorage-system.svc.cluster.local:9090 + - name: OBJECT_STORAGE_INSTANCE + value: object-storage.objectstorage-system.svc.cluster.local:80 + image: ghcr.io/labring/sealos-minio-service:latest + imagePullPolicy: Always + name: object-storage-monitor + ports: + - containerPort: 9090 + protocol: TCP + resources: + limits: + cpu: 500m + memory: 1024Mi + requests: + cpu: 5m + memory: 64Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + runAsNonRoot: true + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + volumeMounts: + - mountPath: /config + name: config-vol + dnsPolicy: ClusterFirst + restartPolicy: Always + volumes: + - configMap: + defaultMode: 420 + name: object-storage-monitor-config + name: config-vol +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app: object-storage-monitor + name: object-storage-monitor + namespace: objectstorage-system +spec: + ports: + - name: http + port: 9090 + protocol: TCP + targetPort: 9090 + selector: + app: object-storage-monitor diff --git a/service/minio/main.go b/service/minio/main.go new file mode 100644 index 00000000000..b0edc2ef985 --- /dev/null +++ b/service/minio/main.go @@ -0,0 +1,35 @@ +package main + +import ( + "flag" + "fmt" + "log" + "os" + + minioserver "github.com/labring/sealos/service/minio/server" + "github.com/labring/sealos/service/pkg/server" +) + +func main() { + log.SetOutput(os.Stdout) + log.SetFlags(log.LstdFlags | log.Lshortfile) + flag.Parse() + + cf := flag.Arg(0) + if cf == "" { + fmt.Println("The config file is not specified") + return + } + + config, err := server.InitConfig(cf) + if err != nil { + fmt.Println(err) + return + } + + rs := minioserver.MinioServer{ + ConfigFile: cf, + } + + rs.Serve(config) +} diff --git a/service/minio/server/server.go b/service/minio/server/server.go new file mode 100644 index 00000000000..4f5b9b41091 --- /dev/null +++ b/service/minio/server/server.go @@ -0,0 +1,38 @@ +package server + +import ( + "fmt" + "net" + "net/http" + + "github.com/labring/sealos/service/pkg/server" +) + +type MinioServer struct { + ConfigFile string +} + +func (rs *MinioServer) Serve(c *server.Config) { + ps, err := server.NewPromServer(c) + if err != nil { + fmt.Printf("Failed to create auth server: %s\n", err) + return + } + + hs := &http.Server{ + Addr: c.Server.ListenAddress, + Handler: ps, + } + + listener, err := net.Listen("tcp", c.Server.ListenAddress) + if err != nil { + fmt.Println(err) + return + } + fmt.Printf("Serve on %s\n", c.Server.ListenAddress) + + if err := hs.Serve(listener); err != nil { + fmt.Println(err) + return + } +} diff --git a/service/database/api/req.go b/service/pkg/api/req.go similarity index 100% rename from service/database/api/req.go rename to service/pkg/api/req.go diff --git a/service/database/request/req.go b/service/pkg/request/req.go similarity index 98% rename from service/database/request/req.go rename to service/pkg/request/req.go index 43ca12bc478..e00f072d1fa 100644 --- a/service/database/request/req.go +++ b/service/pkg/request/req.go @@ -10,7 +10,7 @@ import ( "os" "strings" - "github.com/labring/sealos/service/database/api" + "github.com/labring/sealos/service/pkg/api" ) func Request(addr string, params *bytes.Buffer) ([]byte, error) { diff --git a/service/database/server/config.go b/service/pkg/server/config.go similarity index 100% rename from service/database/server/config.go rename to service/pkg/server/config.go diff --git a/service/pkg/server/server.go b/service/pkg/server/server.go new file mode 100644 index 00000000000..53ea30bf08e --- /dev/null +++ b/service/pkg/server/server.go @@ -0,0 +1,202 @@ +package server + +import ( + "encoding/json" + "fmt" + "log" + "net/http" + "net/url" + "text/template" + + "github.com/labring/sealos/service/pkg/auth" + + "github.com/labring/sealos/service/pkg/api" + "github.com/labring/sealos/service/pkg/request" +) + +type PromServer struct { + Config *Config +} + +func NewPromServer(c *Config) (*PromServer, error) { + ps := &PromServer{ + Config: c, + } + return ps, nil +} + +func (ps *PromServer) Authenticate(pr *api.PromRequest) error { + return auth.Authenticate(pr.NS, pr.Pwd) +} + +func (ps *PromServer) Request(pr *api.PromRequest) (*api.QueryResult, error) { + body, err := request.PrometheusPre(pr) + if err != nil { + return nil, err + } + var result *api.QueryResult + if err := json.Unmarshal(body, &result); err != nil { + return nil, err + } + return result, err +} + +func (ps *PromServer) DBReq(pr *api.PromRequest) (*api.QueryResult, error) { + body, err := request.PrometheusNew(pr) + if err != nil { + return nil, err + } + var result *api.QueryResult + if err := json.Unmarshal(body, &result); err != nil { + return nil, err + } + return result, nil +} + +func (ps *PromServer) ParseRequest(req *http.Request) (*api.PromRequest, error) { + pr := &api.PromRequest{} + + auth := req.Header.Get("Authorization") + + if pwd, err := url.PathUnescape(auth); err == nil { + pr.Pwd = pwd + } else { + return nil, err + } + if pr.Pwd == "" { + return nil, api.ErrEmptyKubeconfig + } + + if err := req.ParseForm(); err != nil { + return nil, err + } + + for key, val := range req.Form { + switch key { + case "query": + pr.Query = val[0] + case "step": + pr.Range.Step = val[0] + case "start": + pr.Range.Start = val[0] + case "end": + pr.Range.End = val[0] + case "time": + pr.Range.Time = val[0] + case "namespace": + pr.NS = val[0] + case "type": + pr.Type = val[0] + case "app": + pr.Cluster = val[0] + } + } + + if pr.NS == "" || pr.Query == "" { + return nil, api.ErrUncompleteParam + } + + return pr, nil +} + +// 获取客户端请求的信息 +func (ps *PromServer) ServeHTTP(rw http.ResponseWriter, req *http.Request) { + pathPrefix := "" + switch { + case req.URL.Path == pathPrefix+"/query": // 将废弃 + ps.doReqPre(rw, req) + case req.URL.Path == pathPrefix+"/q": + ps.doReqNew(rw, req) + default: + http.Error(rw, "Not found", http.StatusNotFound) + return + } +} + +func (ps *PromServer) doReqNew(rw http.ResponseWriter, req *http.Request) { + pr, err := ps.ParseRequest(req) + if err != nil { + http.Error(rw, fmt.Sprintf("Bad request (%s)", err), http.StatusBadRequest) + log.Printf("Bad request (%s)\n", err) + return + } + + if err := ps.Authenticate(pr); err != nil { + http.Error(rw, fmt.Sprintf("Authentication failed (%s)", err), http.StatusInternalServerError) + log.Printf("Authentication failed (%s)\n", err) + return + } + + res, err := ps.DBReq(pr) + if err != nil { + http.Error(rw, fmt.Sprintf("Query failed (%s)", err), http.StatusInternalServerError) + log.Printf("Query failed (%s)\n", err) + return + } + + result, err := json.Marshal(res) + if err != nil { + http.Error(rw, "Result failed (invalid query expression)", http.StatusInternalServerError) + log.Printf("Reulst failed (%s)\n", err) + return + } + + rw.Header().Set("Content-Type", "application/json") + + tmpl := template.New("responseTemplate").Delims("{{", "}}") + tmpl, err = tmpl.Parse(`{{.}}`) + if err != nil { + log.Printf("template failed: %s\n", err) + http.Error(rw, "Internal Server Error", http.StatusInternalServerError) + return + } + if err = tmpl.Execute(rw, string(result)); err != nil { + log.Printf("Reulst failed: %s\n", err) + http.Error(rw, "Internal Server Error", http.StatusInternalServerError) + return + } +} + +func (ps *PromServer) doReqPre(rw http.ResponseWriter, req *http.Request) { + pr, err := ps.ParseRequest(req) + if err != nil { + http.Error(rw, fmt.Sprintf("Bad request (%s)", err), http.StatusBadRequest) + log.Printf("Bad request (%s)\n", err) + return + } + + if err := ps.Authenticate(pr); err != nil { + http.Error(rw, fmt.Sprintf("Authentication failed (%s)", err), http.StatusInternalServerError) + log.Printf("Authentication failed (%s)\n", err) + log.Printf("Kubeconfig (%s)\n", pr.Pwd) + } + + res, err := ps.Request(pr) + if err != nil { + http.Error(rw, fmt.Sprintf("Query failed (%s)", err), http.StatusInternalServerError) + log.Printf("Query failed (%s)\n", err) + return + } + + result, err := json.Marshal(res) + if err != nil { + http.Error(rw, "Result failed (invalid query expression)", http.StatusInternalServerError) + log.Printf("Reulst failed (%s)\n", err) + return + } + + rw.Header().Set("Content-Type", "application/json") + + tmpl := template.New("responseTemplate").Delims("{{", "}}") + tmpl, err = tmpl.Parse(`{{.}}`) + if err != nil { + log.Printf("template failed: %s\n", err) + http.Error(rw, "Internal Server Error", http.StatusInternalServerError) + return + } + if err = tmpl.Execute(rw, string(result)); err != nil { + log.Printf("Reulst failed: %s\n", err) + http.Error(rw, "Internal Server Error", http.StatusInternalServerError) + return + } +}