Kmesh/cmd/command/http_server.go

187 lines
5.7 KiB
Go

/*
* Copyright (c) 2019 Huawei Technologies Co., Ltd.
* 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.
* Author: LemmyHuang
* Create: 2022-03-02
*/
package command
import (
"fmt"
"io/ioutil"
"net/http"
"github.com/golang/protobuf/jsonpb"
"google.golang.org/protobuf/encoding/protojson"
admin_v2 "openeuler.io/mesh/api/v2/admin"
"openeuler.io/mesh/pkg/controller"
"openeuler.io/mesh/pkg/controller/envoy"
"openeuler.io/mesh/pkg/options"
)
type httpServer struct {
mux *http.ServeMux
server *http.Server
}
func newHttpServer() *httpServer {
s := &httpServer{
mux: http.NewServeMux(),
}
s.server = &http.Server{
Addr: adminAddr,
Handler: s.mux,
ReadTimeout: httpTimeout,
WriteTimeout: httpTimeout,
}
s.mux.HandleFunc(patternHelp, httpHelp)
s.mux.HandleFunc(patternOptions, httpOptions)
s.mux.HandleFunc(patternBpfKmeshMaps, httpBpfKmeshMaps)
s.mux.HandleFunc(patternControllerEnvoy, httpControllerEnvoy)
s.mux.HandleFunc(patternControllerKubernetes, httpControllerKubernetes)
return s
}
func httpHelp(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, "\t%s: %s\n", patternHelp,
"print list of commands")
fmt.Fprintf(w, "\t%s: %s\n", patternOptions,
"print config options")
fmt.Fprintf(w, "\t%s: %s\n", patternBpfKmeshMaps,
"print bpf kmesh maps in kernel")
fmt.Fprintf(w, "\t%s: %s\n", patternControllerEnvoy,
"print control-plane in envoy cache")
fmt.Fprintf(w, "\t%s: %s\n", patternControllerKubernetes,
"print control-plane in kubernetes cache")
}
func httpOptions(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
fmt.Fprintln(w, options.String())
}
func httpBpfKmeshMaps(w http.ResponseWriter, r *http.Request) {
client := controller.GetAdsClient()
if client == nil {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(w, "\t%s\n", "invalid ClientMode")
return
} else if client.Event == nil {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintf(w, "\t%s\n", "none client.Event")
return
}
switch r.Method {
case http.MethodGet:
dynamicLd := client.Event.DynamicLoader
staticLd := client.Event.StaticLoader
dynamicRes := &admin_v2.ConfigResources{}
staticRes := &admin_v2.ConfigResources{}
dynamicRes.ClusterConfigs = append(dynamicRes.ClusterConfigs, dynamicLd.ClusterCache.StatusLookup()...)
dynamicRes.ListenerConfigs = append(dynamicRes.ListenerConfigs, dynamicLd.ListenerCache.StatusLookup()...)
dynamicRes.RouteConfigs = append(dynamicRes.RouteConfigs, dynamicLd.RouteCache.StatusLookup()...)
envoy.SetApiVersionInfo(dynamicRes)
staticRes.ClusterConfigs = append(staticRes.ClusterConfigs, staticLd.ClusterCache.StatusLookup()...)
staticRes.ListenerConfigs = append(staticRes.ListenerConfigs, staticLd.ListenerCache.StatusLookup()...)
staticRes.RouteConfigs = append(staticRes.RouteConfigs, staticLd.RouteCache.StatusLookup()...)
envoy.SetApiVersionInfo(staticRes)
fmt.Fprintln(w, protojson.Format(&admin_v2.ConfigDump{
StaticResources: staticRes,
DynamicResources: dynamicRes,
}))
case http.MethodPost:
if controller.IsAdsEnable() {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintln(w, "This operation is not supported, because kmesh starts with -enable-ads=true.")
return
}
dump := &admin_v2.ConfigDump{}
content, err := ioutil.ReadAll(r.Body)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintln(w, "body read failed")
return
}
if err = jsonpb.UnmarshalString(string(content), dump); err != nil {
w.WriteHeader(http.StatusBadRequest)
fmt.Fprintln(w, "body unmarshal failed")
return
}
client.Event.NewAdminRequest(dump.GetStaticResources())
default:
w.WriteHeader(http.StatusNotFound)
return
}
w.WriteHeader(http.StatusOK)
return
}
func httpControllerEnvoy(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
client := controller.GetAdsClient()
if client == nil {
fmt.Fprintf(w, "\t%s\n", "invalid bpf.Config.ClientMode")
return
}
dynamicLd := client.Event.DynamicLoader
staticLd := client.Event.StaticLoader
dynamicRes := &admin_v2.ConfigResources{}
staticRes := &admin_v2.ConfigResources{}
dynamicRes.ClusterConfigs = append(dynamicRes.ClusterConfigs, dynamicLd.ClusterCache.StatusRead()...)
dynamicRes.ListenerConfigs = append(dynamicRes.ListenerConfigs, dynamicLd.ListenerCache.StatusRead()...)
dynamicRes.RouteConfigs = append(dynamicRes.RouteConfigs, dynamicLd.RouteCache.StatusRead()...)
envoy.SetApiVersionInfo(dynamicRes)
staticRes.ClusterConfigs = append(staticRes.ClusterConfigs, staticLd.ClusterCache.StatusRead()...)
staticRes.ListenerConfigs = append(staticRes.ListenerConfigs, staticLd.ListenerCache.StatusRead()...)
staticRes.RouteConfigs = append(staticRes.RouteConfigs, staticLd.RouteCache.StatusRead()...)
envoy.SetApiVersionInfo(staticRes)
fmt.Fprintln(w, protojson.Format(&admin_v2.ConfigDump{
StaticResources: staticRes,
DynamicResources: dynamicRes,
}))
}
func httpControllerKubernetes(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotImplemented)
fmt.Fprintf(w, "%s: %s\n", patternControllerKubernetes,
"TODO")
}
var cmdServer = newHttpServer()
func StartServer() error {
go cmdServer.server.ListenAndServe()
return nil
}
func StopServer() error {
return cmdServer.server.Close()
}