Rainbond/api/handler/gateway_action.go

544 lines
15 KiB
Go
Raw Normal View History

2018-11-21 15:04:03 +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 handler
import (
2018-11-21 17:15:40 +08:00
"fmt"
2018-12-04 13:43:15 +08:00
"os"
"strconv"
"strings"
2018-11-26 18:08:16 +08:00
"github.com/Sirupsen/logrus"
2018-11-21 15:04:03 +08:00
apimodel "github.com/goodrain/rainbond/api/model"
"github.com/goodrain/rainbond/db"
"github.com/goodrain/rainbond/db/model"
2018-12-04 13:43:15 +08:00
"github.com/goodrain/rainbond/mq/client"
2018-11-21 15:04:03 +08:00
"github.com/goodrain/rainbond/util"
"github.com/jinzhu/gorm"
)
2018-11-26 02:19:08 +08:00
// GatewayAction -
2018-11-21 15:04:03 +08:00
type GatewayAction struct {
dbmanager db.Manager
2018-12-04 13:43:15 +08:00
mqclient client.MQClient
2018-11-21 15:04:03 +08:00
}
2018-11-26 02:19:08 +08:00
//CreateGatewayManager creates gateway manager.
2018-12-04 13:43:15 +08:00
func CreateGatewayManager(dbmanager db.Manager, mqclient client.MQClient) *GatewayAction {
2018-11-21 15:04:03 +08:00
return &GatewayAction{
dbmanager: dbmanager,
2018-12-04 13:43:15 +08:00
mqclient: mqclient,
2018-11-21 15:04:03 +08:00
}
}
2018-11-26 02:19:08 +08:00
// AddHTTPRule adds http rule to db if it doesn't exists.
func (g *GatewayAction) AddHTTPRule(req *apimodel.AddHTTPRuleStruct) (string, error) {
2018-11-23 20:39:34 +08:00
httpRule := &model.HTTPRule{
UUID: req.HTTPRuleID,
2018-11-22 10:38:55 +08:00
ServiceID: req.ServiceID,
ContainerPort: req.ContainerPort,
Domain: req.Domain,
Path: req.Path,
Header: req.Header,
Cookie: req.Cookie,
2018-12-04 17:11:15 +08:00
Weight: req.Weight,
2018-11-22 10:38:55 +08:00
IP: req.IP,
CertificateID: req.CertificateID,
2018-11-22 09:34:00 +08:00
}
// begin transaction
tx := db.GetManager().Begin()
if err := db.GetManager().HTTPRuleDaoTransactions(tx).AddModel(httpRule); err != nil {
2018-11-22 09:34:00 +08:00
tx.Rollback()
return "", err
2018-11-22 09:34:00 +08:00
}
if strings.Replace(req.CertificateID, " ", "", -1) != "" {
2018-11-29 11:46:46 +08:00
cert := &model.Certificate{
UUID: req.CertificateID,
CertificateName: fmt.Sprintf("cert-%s", util.NewUUID()[0:8]),
Certificate: req.Certificate,
PrivateKey: req.PrivateKey,
}
2018-11-29 18:12:26 +08:00
if err := db.GetManager().CertificateDaoTransactions(tx).AddOrUpdate(cert); err != nil {
2018-11-29 11:46:46 +08:00
tx.Rollback()
return "", err
}
2018-11-22 09:34:00 +08:00
}
for _, ruleExtension := range req.RuleExtensions {
re := &model.RuleExtension{
2018-11-22 10:38:55 +08:00
UUID: util.NewUUID(),
2018-11-22 09:34:00 +08:00
RuleID: httpRule.UUID,
2018-11-22 10:38:55 +08:00
Key: ruleExtension.Key,
Value: ruleExtension.Value,
2018-11-22 09:34:00 +08:00
}
if err := db.GetManager().RuleExtensionDaoTransactions(tx).AddModel(re); err != nil {
tx.Rollback()
return "", err
2018-11-22 09:34:00 +08:00
}
}
// end transaction
if err := tx.Commit().Error; err != nil {
tx.Rollback()
return "", err
2018-11-22 09:34:00 +08:00
}
return httpRule.ServiceID, nil
2018-11-21 15:04:03 +08:00
}
2018-11-26 02:19:08 +08:00
// UpdateHTTPRule updates http rule
func (g *GatewayAction) UpdateHTTPRule(req *apimodel.UpdateHTTPRuleStruct) (string, error) {
2018-11-22 10:38:55 +08:00
tx := db.GetManager().Begin()
rule, err := g.dbmanager.HTTPRuleDaoTransactions(tx).GetHTTPRuleByID(req.HTTPRuleID)
2018-11-21 17:15:40 +08:00
if err != nil {
2018-11-22 09:34:00 +08:00
tx.Rollback()
return "", err
2018-11-21 17:15:40 +08:00
}
if rule == nil {
2018-11-22 09:34:00 +08:00
tx.Rollback()
return "", fmt.Errorf("HTTPRule dosen't exist based on uuid(%s)", req.HTTPRuleID)
2018-11-21 17:15:40 +08:00
}
if strings.Replace(req.CertificateID, " ", "", -1) != "" {
// delete old Certificate
if err := g.dbmanager.CertificateDaoTransactions(tx).DeleteCertificateByID(rule.CertificateID); err != nil {
tx.Rollback()
return "", err
2018-11-22 09:34:00 +08:00
}
// add new certificate
cert := &model.Certificate{
UUID: req.CertificateID,
CertificateName: fmt.Sprintf("cert-%s", util.NewUUID()[0:8]),
Certificate: req.Certificate,
PrivateKey: req.PrivateKey,
}
2018-11-29 18:12:26 +08:00
if err := g.dbmanager.CertificateDaoTransactions(tx).AddOrUpdate(cert); err != nil {
tx.Rollback()
return "", err
}
rule.CertificateID = req.CertificateID
}
if len(req.RuleExtensions) > 0 {
// delete old RuleExtensions
if err := g.dbmanager.RuleExtensionDaoTransactions(tx).DeleteRuleExtensionByRuleID(rule.UUID); err != nil {
2018-11-22 09:34:00 +08:00
tx.Rollback()
return "", err
2018-11-22 09:34:00 +08:00
}
// add new rule extensions
for _, ruleExtension := range req.RuleExtensions {
re := &model.RuleExtension{
UUID: util.NewUUID(),
RuleID: rule.UUID,
Key: ruleExtension.Key,
Value: ruleExtension.Value,
}
if err := db.GetManager().RuleExtensionDaoTransactions(tx).AddModel(re); err != nil {
tx.Rollback()
return "", err
}
}
2018-11-22 09:34:00 +08:00
}
// update http rule
if req.ServiceID != "" {
rule.ServiceID = req.ServiceID
}
if req.ContainerPort != 0 {
rule.ContainerPort = req.ContainerPort
}
if req.Domain != "" {
rule.Domain = req.Domain
}
if req.Path != "" {
rule.Path = req.Path
}
if req.Header != "" {
rule.Header = req.Header
}
if req.Cookie != "" {
rule.Cookie = req.Cookie
}
2018-12-04 17:11:15 +08:00
if req.Weight > 0 {
rule.Weight = req.Weight
}
if req.IP != "" {
rule.IP = req.IP
}
if err := db.GetManager().HTTPRuleDaoTransactions(tx).UpdateModel(rule); err != nil {
2018-11-22 09:34:00 +08:00
tx.Rollback()
return "", err
2018-11-22 09:34:00 +08:00
}
// end transaction
if err := tx.Commit().Error; err != nil {
tx.Rollback()
return "", err
2018-11-22 09:34:00 +08:00
}
return rule.ServiceID, nil
2018-11-21 17:15:40 +08:00
}
2018-11-26 02:19:08 +08:00
// DeleteHTTPRule deletes http rule, including certificate and rule extensions
func (g *GatewayAction) DeleteHTTPRule(req *apimodel.DeleteHTTPRuleStruct) (string, error) {
2018-11-21 17:57:48 +08:00
// begin transaction
tx := db.GetManager().Begin()
// delete http rule
httpRule, err := g.dbmanager.HTTPRuleDaoTransactions(tx).GetHTTPRuleByID(req.HTTPRuleID)
2018-11-29 18:12:26 +08:00
svcID := httpRule.ServiceID
2018-11-21 17:57:48 +08:00
if err != nil {
tx.Rollback()
return "", err
2018-11-21 17:57:48 +08:00
}
if err := g.dbmanager.HTTPRuleDaoTransactions(tx).DeleteHTTPRuleByID(httpRule.UUID); err != nil {
2018-11-22 09:34:00 +08:00
tx.Rollback()
return "", err
2018-11-22 09:34:00 +08:00
}
2018-11-21 17:57:48 +08:00
// delete certificate
if err := g.dbmanager.CertificateDaoTransactions(tx).DeleteCertificateByID(httpRule.CertificateID); err != nil {
tx.Rollback()
return "", err
2018-11-21 17:57:48 +08:00
}
// delete rule extension
if err := g.dbmanager.RuleExtensionDaoTransactions(tx).DeleteRuleExtensionByRuleID(httpRule.UUID); err != nil {
tx.Rollback()
return "", err
2018-11-21 17:57:48 +08:00
}
// end transaction
if err := tx.Commit().Error; err != nil {
return "", err
2018-11-21 17:57:48 +08:00
}
2018-11-29 18:12:26 +08:00
return svcID, nil
2018-11-21 17:57:48 +08:00
}
2018-11-21 17:15:40 +08:00
// AddCertificate adds certificate to db if it doesn't exists
func (g *GatewayAction) AddCertificate(req *apimodel.AddHTTPRuleStruct, tx *gorm.DB) error {
2018-11-21 17:15:40 +08:00
cert := &model.Certificate{
2018-11-21 17:57:48 +08:00
UUID: req.CertificateID,
CertificateName: fmt.Sprintf("cert-%s", util.NewUUID()[0:8]),
2018-11-21 17:57:48 +08:00
Certificate: req.Certificate,
PrivateKey: req.PrivateKey,
2018-11-21 17:15:40 +08:00
}
return g.dbmanager.CertificateDaoTransactions(tx).AddModel(cert)
}
2018-11-26 02:19:08 +08:00
// UpdateCertificate updates certificate for http rule
func (g *GatewayAction) UpdateCertificate(req apimodel.AddHTTPRuleStruct, httpRule *model.HTTPRule,
2018-11-21 19:51:40 +08:00
tx *gorm.DB) error {
2018-11-21 17:15:40 +08:00
// delete old certificate
cert, err := g.dbmanager.CertificateDaoTransactions(tx).GetCertificateByID(req.CertificateID)
if err != nil {
return err
}
if cert == nil {
return fmt.Errorf("Certificate doesn't exist based on certificateID(%s)", req.CertificateID)
}
cert.CertificateName = fmt.Sprintf("cert-%s", util.NewUUID()[0:8])
2018-11-21 17:15:40 +08:00
cert.Certificate = req.Certificate
cert.PrivateKey = req.PrivateKey
return g.dbmanager.CertificateDaoTransactions(tx).UpdateModel(cert)
2018-11-21 15:04:03 +08:00
}
2018-11-26 02:19:08 +08:00
// AddTCPRule adds tcp rule.
func (g *GatewayAction) AddTCPRule(req *apimodel.AddTCPRuleStruct) (string, error) {
// begin transaction
tx := db.GetManager().Begin()
2018-12-19 13:53:11 +08:00
// add port
port := &model.TenantServiceLBMappingPort{
ServiceID: req.ServiceID,
Port: req.Port,
ContainerPort: req.ContainerPort,
}
err := g.dbmanager.TenantServiceLBMappingPortDaoTransactions(tx).AddModel(port)
if err != nil {
tx.Rollback()
return "", err
}
// add tcp rule
2018-11-23 20:39:34 +08:00
tcpRule := &model.TCPRule{
UUID: req.TCPRuleID,
2018-11-22 10:38:55 +08:00
ServiceID: req.ServiceID,
ContainerPort: req.ContainerPort,
IP: req.IP,
Port: req.Port,
2018-11-21 19:51:40 +08:00
}
if err := g.dbmanager.TCPRuleDaoTransactions(tx).AddModel(tcpRule); err != nil {
2018-11-21 20:14:13 +08:00
tx.Rollback()
return "", err
2018-11-21 19:51:40 +08:00
}
// add rule extensions
for _, ruleExtension := range req.RuleExtensions {
re := &model.RuleExtension{
2018-11-21 20:14:13 +08:00
UUID: util.NewUUID(),
RuleID: tcpRule.UUID,
Value: ruleExtension.Value,
}
if err := g.dbmanager.RuleExtensionDaoTransactions(tx).AddModel(re); err != nil {
tx.Rollback()
return "", err
2018-11-21 20:14:13 +08:00
}
}
// end transaction
if err := tx.Commit().Error; err != nil {
return "", err
2018-11-21 20:14:13 +08:00
}
return tcpRule.ServiceID, nil
2018-11-21 20:14:13 +08:00
}
2018-11-26 02:19:08 +08:00
// UpdateTCPRule updates a tcp rule
func (g *GatewayAction) UpdateTCPRule(req *apimodel.UpdateTCPRuleStruct, minPort int) (string, error) {
2018-11-21 20:14:13 +08:00
// begin transaction
tx := db.GetManager().Begin()
// get old tcp rule
tcpRule, err := g.dbmanager.TCPRuleDaoTransactions(tx).GetTCPRuleByID(req.TCPRuleID)
2018-11-21 20:14:13 +08:00
if err != nil {
tx.Rollback()
return "", err
2018-11-21 20:14:13 +08:00
}
if len(req.RuleExtensions) > 0 {
// delete old rule extensions
if err := g.dbmanager.RuleExtensionDaoTransactions(tx).DeleteRuleExtensionByRuleID(tcpRule.UUID); err != nil {
tx.Rollback()
return "", err
}
// add new rule extensions
for _, ruleExtension := range req.RuleExtensions {
re := &model.RuleExtension{
UUID: util.NewUUID(),
RuleID: tcpRule.UUID,
Value: ruleExtension.Value,
}
if err := g.dbmanager.RuleExtensionDaoTransactions(tx).AddModel(re); err != nil {
tx.Rollback()
return "", err
}
}
2018-11-21 20:14:13 +08:00
}
// update tcp rule
if req.ServiceID != "" {
tcpRule.ServiceID = req.ServiceID
2018-11-21 20:14:13 +08:00
}
if req.ContainerPort != 0 {
tcpRule.ContainerPort = req.ContainerPort
}
2018-12-19 13:53:11 +08:00
if req.IP != "" {
tcpRule.IP = req.IP
2018-12-18 20:55:12 +08:00
}
2018-12-19 13:53:11 +08:00
if req.Port > minPort {
// get old port
port, err := g.dbmanager.TenantServiceLBMappingPortDaoTransactions(tx).GetLBMappingPortByServiceIDAndPort(
tcpRule.ServiceID, tcpRule.Port)
if err != nil {
tx.Rollback()
return "", err
}
// check
// update port
port.Port = req.Port
if err := g.dbmanager.TenantServiceLBMappingPortDaoTransactions(tx).UpdateModel(port); err != nil {
tx.Rollback()
return "", err
}
tcpRule.Port = req.Port
} else {
logrus.Warningf("Expected external port > %d, but got %d", minPort, req.Port)
2018-12-18 20:55:12 +08:00
}
if err := g.dbmanager.TCPRuleDaoTransactions(tx).UpdateModel(tcpRule); err != nil {
tx.Rollback()
return "", err
2018-11-21 19:51:40 +08:00
}
// end transaction
if err := tx.Commit().Error; err != nil {
2018-11-21 20:14:13 +08:00
tx.Rollback()
return "", err
2018-11-21 19:51:40 +08:00
}
return tcpRule.ServiceID, nil
2018-11-21 19:51:40 +08:00
}
2018-11-26 02:19:08 +08:00
// DeleteTCPRule deletes a tcp rule
func (g *GatewayAction) DeleteTCPRule(req *apimodel.DeleteTCPRuleStruct) (string, error) {
2018-11-21 20:33:37 +08:00
// begin transaction
tx := db.GetManager().Begin()
tcpRule, err := db.GetManager().TCPRuleDaoTransactions(tx).GetTCPRuleByID(req.TCPRuleID)
2018-11-21 20:33:37 +08:00
if err != nil {
tx.Rollback()
return "", err
2018-11-21 20:33:37 +08:00
}
// delete rule extensions
if err := db.GetManager().RuleExtensionDaoTransactions(tx).DeleteRuleExtensionByRuleID(tcpRule.UUID); err != nil {
tx.Rollback()
return "", err
2018-11-21 20:33:37 +08:00
}
// delete tcp rule
if err := db.GetManager().TCPRuleDaoTransactions(tx).DeleteTCPRule(tcpRule); err != nil {
2018-11-21 20:33:37 +08:00
tx.Rollback()
return "", err
2018-11-21 20:33:37 +08:00
}
// delete LBMappingPort
err = db.GetManager().TenantServiceLBMappingPortDaoTransactions(tx).DELServiceLBMappingPortByServiceIDAndPort(
tcpRule.ServiceID, tcpRule.Port)
if err != nil {
tx.Rollback()
return "", err
}
2018-11-21 20:33:37 +08:00
// end transaction
if err := tx.Commit().Error; err != nil {
tx.Rollback()
return "", err
2018-11-21 20:33:37 +08:00
}
return tcpRule.ServiceID, nil
2018-11-21 20:33:37 +08:00
}
2018-11-21 17:15:40 +08:00
// AddRuleExtensions adds rule extensions to db if any of they doesn't exists
2018-11-21 19:51:40 +08:00
func (g *GatewayAction) AddRuleExtensions(ruleID string, ruleExtensions []*apimodel.RuleExtensionStruct,
tx *gorm.DB) error {
2018-11-21 15:04:03 +08:00
for _, ruleExtension := range ruleExtensions {
re := &model.RuleExtension{
UUID: util.NewUUID(),
RuleID: ruleID,
Value: ruleExtension.Value,
}
err := g.dbmanager.RuleExtensionDaoTransactions(tx).AddModel(re)
if err != nil {
return err
}
}
return nil
}
2018-11-26 02:19:08 +08:00
// GetAvailablePort returns a available port
func (g *GatewayAction) GetAvailablePort() (int, error) {
mapPorts, err := g.dbmanager.TenantServiceLBMappingPortDao().GetLBPortsASC()
if err != nil {
return 0, err
}
var ports []int
for _, p := range mapPorts {
ports = append(ports, p.Port)
}
maxPort, _ := strconv.Atoi(os.Getenv("MAX_LB_PORT"))
minPort, _ := strconv.Atoi(os.Getenv("MIN_LB_PORT"))
2018-11-26 02:19:08 +08:00
if minPort == 0 {
minPort = 20001
}
if maxPort == 0 {
maxPort = 35000
}
var maxUsePort int
if len(ports) > 0 && ports[len(ports)-1] > minPort {
2018-11-26 02:19:08 +08:00
maxUsePort = ports[len(ports)-1]
} else {
maxUsePort = 20001
}
//顺序分配端口
selectPort := maxUsePort + 1
if selectPort <= maxPort {
return selectPort, nil
}
//捡漏以前端口
selectPort = minPort
for _, p := range ports {
if p == selectPort {
selectPort = selectPort + 1
continue
}
if p > selectPort {
return selectPort, nil
}
selectPort = selectPort + 1
}
if selectPort <= maxPort {
return selectPort, nil
}
return 0, fmt.Errorf("no more lb port can be use,max port is %d", maxPort)
}
// PortExists returns if the port exists
func (g *GatewayAction) PortExists(port int) bool {
return g.dbmanager.TenantServiceLBMappingPortDao().PortExists(port)
}
2018-11-26 18:08:16 +08:00
2018-12-10 21:23:55 +08:00
// SendTask sends apply rules task
2019-03-12 09:59:09 +08:00
func (g *GatewayAction) SendTask(in map[string]interface{}) error {
sid := in["service_id"].(string)
service, err := db.GetManager().TenantServiceDao().GetServiceByID(sid)
2018-11-26 18:08:16 +08:00
if err != nil {
2019-03-12 09:59:09 +08:00
return fmt.Errorf("Unexpected error occurred while getting Service by ServiceID(%s): %v", sid, err)
2018-11-26 18:08:16 +08:00
}
body := make(map[string]interface{})
body["deploy_version"] = service.DeployVersion
2019-03-12 09:59:09 +08:00
for k, v := range in {
body[k] = v
}
2018-12-04 13:43:15 +08:00
err = g.mqclient.SendBuilderTopic(client.TaskStruct{
2018-12-04 18:08:51 +08:00
Topic: client.WorkerTopic,
2018-12-04 13:43:15 +08:00
TaskType: "apply_rule",
TaskBody: body,
})
2018-11-26 18:08:16 +08:00
if err != nil {
2018-12-04 13:43:15 +08:00
return fmt.Errorf("Unexpected error occurred while sending task: %v", err)
2018-11-26 18:08:16 +08:00
}
2018-12-04 13:43:15 +08:00
return nil
2018-11-26 18:08:16 +08:00
}
// TCPAvailable checks if the ip and port for TCP is available.
2018-12-18 20:55:12 +08:00
func (g *GatewayAction) TCPAvailable(ip string, port int, ruleID string) bool {
rule, err := g.dbmanager.TCPRuleDao().GetTCPRuleByID(ruleID)
if err != nil {
2018-12-18 20:55:12 +08:00
logrus.Warningf("error getting TCPRule by UUID(%s)", ruleID)
return false
}
2018-12-18 20:55:12 +08:00
if rule == nil || (rule.IP != ip && rule.Port != port) {
ipport, err := g.dbmanager.IPPortDao().GetIPPortByIPAndPort(ip, port)
if err != nil {
logrus.Warningf("error getting IPPort(ip=%s, port=%d)", ip, port)
return false
}
if ipport != nil {
return false
}
}
2018-12-18 20:55:12 +08:00
if rule == nil || rule.IP != "0.0.0.0" {
ipport, err := g.dbmanager.IPPortDao().GetIPPortByIPAndPort("0.0.0.0", port)
2018-12-18 19:43:17 +08:00
if err != nil {
logrus.Warningf("error getting IPPort(ip=%s, port=%d)", "0.0.0.0", port)
return false
}
if ipport != nil {
return false
}
}
return true
}
2018-12-19 10:35:04 +08:00
// AddIPPool adds AddIPPool
func (g *GatewayAction) AddIPPool(req *apimodel.IPPoolStruct) error {
ippool := &model.IPPool{
2019-02-12 15:40:42 +08:00
EID: req.EID,
2018-12-19 10:35:04 +08:00
CIDR: req.CIDR,
}
if err := g.dbmanager.IPPoolDao().AddModel(ippool); err != nil {
return err
}
return nil
2019-02-12 15:40:42 +08:00
}