2018-11-17 18:08:33 +08:00
|
|
|
// RAINBOND, Application Management Platform
|
|
|
|
// Copyright (C) 2014-2017 Goodrain Co., Ltd.
|
|
|
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version. For any non-GPL usage of Rainbond,
|
|
|
|
// one or multiple Commercial Licenses authorized by Goodrain Co., Ltd.
|
|
|
|
// must be obtained first.
|
|
|
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
package server
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"strings"
|
2018-11-22 10:44:12 +08:00
|
|
|
"time"
|
|
|
|
|
2018-11-17 18:08:33 +08:00
|
|
|
"github.com/Sirupsen/logrus"
|
2019-03-08 14:46:11 +08:00
|
|
|
"github.com/eapache/channels"
|
2018-11-17 18:08:33 +08:00
|
|
|
"github.com/goodrain/rainbond/cmd/worker/option"
|
2019-03-01 13:27:27 +08:00
|
|
|
"github.com/goodrain/rainbond/discover.v2"
|
2019-01-09 14:07:10 +08:00
|
|
|
"github.com/goodrain/rainbond/util"
|
2018-11-17 18:08:33 +08:00
|
|
|
"github.com/goodrain/rainbond/worker/appm/store"
|
2019-03-08 14:46:11 +08:00
|
|
|
"github.com/goodrain/rainbond/worker/appm/thirdparty/discovery"
|
|
|
|
"github.com/goodrain/rainbond/worker/appm/types/v1"
|
2018-11-17 18:08:33 +08:00
|
|
|
"github.com/goodrain/rainbond/worker/server/pb"
|
2019-03-01 13:27:27 +08:00
|
|
|
"google.golang.org/grpc"
|
2018-11-17 18:08:33 +08:00
|
|
|
"google.golang.org/grpc/reflection"
|
|
|
|
)
|
|
|
|
|
|
|
|
//RuntimeServer app runtime grpc server
|
|
|
|
type RuntimeServer struct {
|
|
|
|
ctx context.Context
|
|
|
|
cancel context.CancelFunc
|
|
|
|
store store.Storer
|
|
|
|
conf option.Config
|
|
|
|
server *grpc.Server
|
|
|
|
hostIP string
|
|
|
|
keepalive *discover.KeepAlive
|
2019-03-08 14:46:11 +08:00
|
|
|
|
|
|
|
updateCh *channels.RingChannel
|
2018-11-17 18:08:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
//CreaterRuntimeServer create a runtime grpc server
|
2019-03-08 14:46:11 +08:00
|
|
|
func CreaterRuntimeServer(conf option.Config,
|
|
|
|
store store.Storer,
|
|
|
|
updateCh *channels.RingChannel) *RuntimeServer {
|
2018-11-17 18:08:33 +08:00
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
rs := &RuntimeServer{
|
2019-03-08 14:46:11 +08:00
|
|
|
conf: conf,
|
|
|
|
ctx: ctx,
|
|
|
|
cancel: cancel,
|
|
|
|
server: grpc.NewServer(),
|
|
|
|
hostIP: conf.HostIP,
|
|
|
|
store: store,
|
|
|
|
updateCh: updateCh,
|
2018-11-17 18:08:33 +08:00
|
|
|
}
|
|
|
|
pb.RegisterAppRuntimeSyncServer(rs.server, rs)
|
|
|
|
// Register reflection service on gRPC server.
|
|
|
|
reflection.Register(rs.server)
|
|
|
|
return rs
|
|
|
|
}
|
|
|
|
|
|
|
|
//Start start runtime server
|
|
|
|
func (r *RuntimeServer) Start(errchan chan error) {
|
|
|
|
go func() {
|
|
|
|
lis, err := net.Listen("tcp", fmt.Sprintf("%s:%d", r.conf.HostIP, r.conf.ServerPort))
|
|
|
|
if err != nil {
|
|
|
|
logrus.Errorf("failed to listen: %v", err)
|
|
|
|
errchan <- err
|
|
|
|
}
|
|
|
|
if err := r.server.Serve(lis); err != nil {
|
|
|
|
errchan <- err
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
if err := r.registServer(); err != nil {
|
|
|
|
errchan <- err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//GetAppStatus get app service status
|
2018-11-22 14:33:29 +08:00
|
|
|
func (r *RuntimeServer) GetAppStatus(ctx context.Context, re *pb.ServicesRequest) (*pb.StatusMessage, error) {
|
2019-01-11 09:44:28 +08:00
|
|
|
var servicdIDs []string
|
|
|
|
if re.ServiceIds != "" {
|
|
|
|
servicdIDs = strings.Split(re.ServiceIds, ",")
|
|
|
|
}
|
|
|
|
status := r.store.GetAppServicesStatus(servicdIDs)
|
2018-11-17 18:08:33 +08:00
|
|
|
return &pb.StatusMessage{
|
|
|
|
Status: status,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2019-01-28 16:00:51 +08:00
|
|
|
//GetTenantResource get tenant resource
|
|
|
|
//if TenantId is "" will return the sum of the all tenant
|
|
|
|
func (r *RuntimeServer) GetTenantResource(ctx context.Context, re *pb.TenantRequest) (*pb.TenantResource, error) {
|
|
|
|
var tr pb.TenantResource
|
|
|
|
res := r.store.GetTenantResource(re.TenantId)
|
|
|
|
if res == nil {
|
|
|
|
return &tr, nil
|
|
|
|
}
|
|
|
|
tr.RunningAppNum = int64(len(r.store.GetTenantRunningApp(re.TenantId)))
|
2019-01-28 17:20:58 +08:00
|
|
|
tr.CpuLimit = res.CPULimit
|
|
|
|
tr.CpuRequest = res.CPURequest
|
2019-01-28 16:25:02 +08:00
|
|
|
tr.MemoryLimit = res.MemoryLimit / 1024 / 1024
|
|
|
|
tr.MemoryRequest = res.MemoryRequest / 1024 / 1024
|
2019-01-28 16:00:51 +08:00
|
|
|
return &tr, nil
|
2018-11-17 18:08:33 +08:00
|
|
|
}
|
|
|
|
|
2018-11-22 14:33:29 +08:00
|
|
|
//GetAppPods get app pod list
|
|
|
|
func (r *RuntimeServer) GetAppPods(ctx context.Context, re *pb.ServiceRequest) (*pb.ServiceAppPodList, error) {
|
|
|
|
var Pods []*pb.ServiceAppPod
|
2018-11-27 17:02:32 +08:00
|
|
|
app := r.store.GetAppService(re.ServiceId)
|
2018-11-28 15:37:28 +08:00
|
|
|
if app == nil {
|
|
|
|
return &pb.ServiceAppPodList{
|
|
|
|
Pods: Pods,
|
|
|
|
}, nil
|
|
|
|
}
|
2018-11-27 17:02:32 +08:00
|
|
|
var deployType, deployID string
|
|
|
|
if deployment := app.GetDeployment(); deployment != nil {
|
|
|
|
deployType = "deployment"
|
|
|
|
deployID = deployment.Name
|
|
|
|
}
|
|
|
|
if statefulset := app.GetStatefulSet(); statefulset != nil {
|
|
|
|
deployType = "statefulset"
|
|
|
|
deployID = statefulset.Name
|
|
|
|
}
|
|
|
|
pods := app.GetPods()
|
|
|
|
for _, pod := range pods {
|
|
|
|
var containers = make(map[string]*pb.Container, len(pod.Spec.Containers))
|
|
|
|
for _, container := range pod.Spec.Containers {
|
|
|
|
containers[container.Name] = &pb.Container{
|
|
|
|
ContainerName: container.Name,
|
2019-01-09 14:42:00 +08:00
|
|
|
MemoryLimit: container.Resources.Limits.Memory().Value(),
|
2018-11-22 14:33:29 +08:00
|
|
|
}
|
|
|
|
}
|
2018-11-27 17:02:32 +08:00
|
|
|
Pods = append(Pods, &pb.ServiceAppPod{
|
|
|
|
ServiceId: app.ServiceID,
|
|
|
|
DeployId: deployID,
|
|
|
|
DeployType: deployType,
|
|
|
|
PodIp: pod.Status.PodIP,
|
|
|
|
PodName: pod.Name,
|
|
|
|
PodStatus: string(pod.Status.Phase),
|
|
|
|
Containers: containers,
|
|
|
|
})
|
2018-11-22 14:33:29 +08:00
|
|
|
}
|
2018-11-27 17:02:32 +08:00
|
|
|
|
2018-11-22 14:33:29 +08:00
|
|
|
return &pb.ServiceAppPodList{
|
|
|
|
Pods: Pods,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2018-12-07 15:15:52 +08:00
|
|
|
//GetDeployInfo get deploy info
|
|
|
|
func (r *RuntimeServer) GetDeployInfo(ctx context.Context, re *pb.ServiceRequest) (*pb.DeployInfo, error) {
|
|
|
|
var deployinfo pb.DeployInfo
|
|
|
|
appService := r.store.GetAppService(re.ServiceId)
|
|
|
|
if appService != nil {
|
|
|
|
deployinfo.Namespace = appService.TenantID
|
|
|
|
if appService.GetStatefulSet() != nil {
|
|
|
|
deployinfo.Statefuleset = appService.GetStatefulSet().Name
|
|
|
|
}
|
|
|
|
if appService.GetDeployment() != nil {
|
|
|
|
deployinfo.Deployment = appService.GetDeployment().Name
|
|
|
|
}
|
|
|
|
if services := appService.GetServices(); services != nil {
|
|
|
|
service := make(map[string]string, len(services))
|
|
|
|
for _, s := range services {
|
|
|
|
service[s.Name] = s.Name
|
|
|
|
}
|
|
|
|
deployinfo.Services = service
|
|
|
|
}
|
|
|
|
if secrets := appService.GetSecrets(); secrets != nil {
|
|
|
|
secretsinfo := make(map[string]string, len(secrets))
|
|
|
|
for _, s := range secrets {
|
|
|
|
secretsinfo[s.Name] = s.Name
|
|
|
|
}
|
|
|
|
deployinfo.Secrets = secretsinfo
|
|
|
|
}
|
|
|
|
if ingresses := appService.GetIngress(); ingresses != nil {
|
|
|
|
ingress := make(map[string]string, len(ingresses))
|
|
|
|
for _, s := range ingresses {
|
|
|
|
ingress[s.Name] = s.Name
|
|
|
|
}
|
|
|
|
deployinfo.Ingresses = ingress
|
|
|
|
}
|
|
|
|
if pods := appService.GetPods(); pods != nil {
|
|
|
|
podNames := make(map[string]string, len(pods))
|
|
|
|
for _, s := range pods {
|
|
|
|
podNames[s.Name] = s.Name
|
|
|
|
}
|
|
|
|
deployinfo.Pods = podNames
|
|
|
|
}
|
|
|
|
if rss := appService.GetReplicaSets(); rss != nil {
|
|
|
|
rsnames := make(map[string]string, len(rss))
|
|
|
|
for _, s := range rss {
|
|
|
|
rsnames[s.Name] = s.Name
|
|
|
|
}
|
|
|
|
deployinfo.Replicatset = rsnames
|
|
|
|
}
|
2018-12-08 12:58:40 +08:00
|
|
|
deployinfo.Status = appService.GetServiceStatus()
|
2018-12-07 15:15:52 +08:00
|
|
|
}
|
|
|
|
return &deployinfo, nil
|
|
|
|
}
|
|
|
|
|
2018-11-17 18:08:33 +08:00
|
|
|
//registServer
|
|
|
|
//regist sync server to etcd
|
|
|
|
func (r *RuntimeServer) registServer() error {
|
2018-11-22 10:44:12 +08:00
|
|
|
if !r.store.Ready() {
|
|
|
|
util.Exec(r.ctx, func() error {
|
|
|
|
if r.store.Ready() {
|
|
|
|
return fmt.Errorf("Ready")
|
|
|
|
}
|
|
|
|
logrus.Debugf("store module is not ready,runtime server is waiting")
|
|
|
|
return nil
|
|
|
|
}, time.Second*3)
|
|
|
|
}
|
2018-11-17 18:08:33 +08:00
|
|
|
if r.keepalive == nil {
|
|
|
|
keepalive, err := discover.CreateKeepAlive(r.conf.EtcdEndPoints, "app_sync_runtime_server", "", r.conf.HostIP, r.conf.ServerPort)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("create app sync server keepalive error,%s", err.Error())
|
|
|
|
}
|
|
|
|
r.keepalive = keepalive
|
|
|
|
}
|
|
|
|
return r.keepalive.Start()
|
|
|
|
}
|
2019-03-08 14:46:11 +08:00
|
|
|
|
|
|
|
// ListThirdPartyEndpoints returns a collection of third-part endpoints.
|
|
|
|
func (r *RuntimeServer) ListThirdPartyEndpoints(ctx context.Context, re *pb.ServiceRequest) (*pb.ThirdPartyEndpoints, error) {
|
|
|
|
as := r.store.GetAppService(re.ServiceId)
|
|
|
|
if as == nil {
|
2019-03-09 21:54:17 +08:00
|
|
|
return new(pb.ThirdPartyEndpoints), nil
|
2019-03-08 14:46:11 +08:00
|
|
|
}
|
|
|
|
var pbeps []*pb.ThirdPartyEndpoint
|
|
|
|
for _, ep := range as.GetRbdEndpionts() {
|
|
|
|
pbep := &pb.ThirdPartyEndpoint{
|
|
|
|
Uuid: ep.UUID,
|
|
|
|
Sid: ep.Sid,
|
|
|
|
Ip: ep.IP,
|
|
|
|
Port: int32(ep.Port),
|
|
|
|
Status: ep.Status,
|
|
|
|
IsOnline: ep.IsOnline,
|
|
|
|
}
|
|
|
|
pbeps = append(pbeps, pbep)
|
|
|
|
}
|
|
|
|
return &pb.ThirdPartyEndpoints{
|
|
|
|
Obj: pbeps,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddThirdPartyEndpoint creates a create event.
|
2019-03-09 21:54:17 +08:00
|
|
|
func (r *RuntimeServer) AddThirdPartyEndpoint(ctx context.Context, re *pb.AddThirdPartyEndpointsReq) (*pb.Empty, error) {
|
2019-03-08 14:46:11 +08:00
|
|
|
as := r.store.GetAppService(re.Sid)
|
|
|
|
if as == nil {
|
2019-03-09 21:54:17 +08:00
|
|
|
return new(pb.Empty), nil
|
2019-03-08 14:46:11 +08:00
|
|
|
}
|
|
|
|
rbdep := &v1.RbdEndpoint{
|
|
|
|
UUID: re.Uuid,
|
|
|
|
Sid: re.Sid,
|
|
|
|
IP: re.Ip,
|
|
|
|
Port: int(re.Port),
|
|
|
|
Status: "healthy",
|
|
|
|
IsOnline: re.IsOnline,
|
|
|
|
}
|
|
|
|
r.updateCh.In() <- discovery.Event{
|
|
|
|
Type: discovery.CreateEvent,
|
|
|
|
Obj: rbdep,
|
|
|
|
}
|
2019-03-09 21:54:17 +08:00
|
|
|
return new(pb.Empty), nil
|
2019-03-08 14:46:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// UpdThirdPartyEndpoint creates a update event.
|
2019-03-09 21:54:17 +08:00
|
|
|
func (r *RuntimeServer) UpdThirdPartyEndpoint(ctx context.Context, re *pb.UpdThirdPartyEndpointsReq) (*pb.Empty, error) {
|
2019-03-08 14:46:11 +08:00
|
|
|
as := r.store.GetAppService(re.Sid)
|
|
|
|
if as == nil {
|
2019-03-09 21:54:17 +08:00
|
|
|
return new(pb.Empty), nil
|
2019-03-08 14:46:11 +08:00
|
|
|
}
|
|
|
|
rbdep := &v1.RbdEndpoint{
|
|
|
|
UUID: re.Uuid,
|
|
|
|
Sid: re.Sid,
|
|
|
|
IP: re.Ip,
|
|
|
|
Port: int(re.Port),
|
|
|
|
IsOnline: re.IsOnline,
|
|
|
|
}
|
|
|
|
r.updateCh.In() <- discovery.Event{
|
|
|
|
Type: discovery.UpdateEvent,
|
|
|
|
Obj: rbdep,
|
|
|
|
}
|
2019-03-09 21:54:17 +08:00
|
|
|
return new(pb.Empty), nil
|
2019-03-08 14:46:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// DelThirdPartyEndpoint creates a delete event.
|
2019-03-09 21:54:17 +08:00
|
|
|
func (r *RuntimeServer) DelThirdPartyEndpoint(ctx context.Context, re *pb.DelThirdPartyEndpointsReq) (*pb.Empty, error) {
|
2019-03-08 14:46:11 +08:00
|
|
|
as := r.store.GetAppService(re.Sid)
|
|
|
|
if as == nil {
|
2019-03-09 21:54:17 +08:00
|
|
|
return new(pb.Empty), nil
|
2019-03-08 14:46:11 +08:00
|
|
|
}
|
|
|
|
r.updateCh.In() <- discovery.Event{
|
|
|
|
Type: discovery.DeleteEvent,
|
|
|
|
Obj: &v1.RbdEndpoint{
|
|
|
|
UUID: re.Uuid,
|
|
|
|
Sid: re.Sid,
|
|
|
|
},
|
|
|
|
}
|
2019-03-09 21:54:17 +08:00
|
|
|
return new(pb.Empty), nil
|
2019-03-08 14:46:11 +08:00
|
|
|
}
|