Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 56 additions & 6 deletions haproxy_manager/link.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,6 @@ func (s Manager) DeleteTCPLink(transaction_id string, backend_name string, port
return nil
}

// TODO: Support other http ports except 80 for Redirect Rules
// Add HTTP Redirect Rule
func (s Manager) AddHTTPRedirectRule(transaction_id string, match_domain string, redirect_url string) error {
if strings.TrimSpace(match_domain) == "" {
Expand All @@ -302,9 +301,9 @@ func (s Manager) AddHTTPRedirectRule(transaction_id string, match_domain string,
"redir_code": 302,
"redir_type": "location",
"redir_value": redirect_url,
"index": 1,
"index": 0,
"cond": "if",
"cond_test": `{ hdr(host) -i ` + strings.TrimSpace(match_domain) + ` }`,
"cond_test": `{ hdr(host) -i ` + strings.TrimSpace(match_domain) + ` } !letsencrypt-acl`,
}
// Create request bytes
add_http_redirect_rule_request_body_bytes, err := json.Marshal(add_http_redirect_rule_request_body)
Expand Down Expand Up @@ -338,9 +337,9 @@ func (s Manager) AddHTTPSRedirectRule(transaction_id string, match_domain string
"redir_code": 302,
"redir_type": "location",
"redir_value": redirect_url,
"index": 1,
"index": 0,
"cond": "if",
"cond_test": `{ hdr(host) -i ` + strings.TrimSpace(match_domain) + ` }`,
"cond_test": `{ hdr(host) -i ` + strings.TrimSpace(match_domain) + ` } !letsencrypt-acl`,
}
// Create request bytes
add_https_redirect_rule_request_body_bytes, err := json.Marshal(add_https_redirect_rule_request_body)
Expand Down Expand Up @@ -386,7 +385,7 @@ func (s Manager) DeleteHTTPRedirectRule(transaction_id string, match_domain stri
get_http_redirect_rules := get_http_redirect_rules_res_body_json["data"].([]interface{})
for _, http_redirect_rule := range get_http_redirect_rules {
http_redirect_rule_item := http_redirect_rule.(map[string]interface{})
if http_redirect_rule_item["cond_test"] == `{ hdr(host) -i `+strings.TrimSpace(match_domain)+` }` {
if http_redirect_rule_item["cond_test"] == `{ hdr(host) -i `+strings.TrimSpace(match_domain)+` } !letsencrypt-acl` {
index = int(http_redirect_rule_item["index"].(float64))
break
}
Expand All @@ -406,3 +405,54 @@ func (s Manager) DeleteHTTPRedirectRule(transaction_id string, match_domain stri
}
return nil
}

// Delete HTTPS Redirect Rule
func (s Manager) DeleteHTTPSRedirectRule(transaction_id string, match_domain string) error {
if strings.TrimSpace(match_domain) == "" {
return errors.New("match domain is required")
}
// Fetch all HTTPS Redirect Rules
get_https_redirect_rules_request_query_params := QueryParameters{}
get_https_redirect_rules_request_query_params.add("transaction_id", transaction_id)
get_https_redirect_rules_request_query_params.add("parent_name", "fe_https")
get_https_redirect_rules_request_query_params.add("parent_type", "frontend")
get_https_redirect_rules_res, get_https_redirect_rules_err := s.getRequest("/services/haproxy/configuration/http_request_rules", get_https_redirect_rules_request_query_params)
if get_https_redirect_rules_err != nil || !isValidStatusCode(get_https_redirect_rules_res.StatusCode) {
return errors.New("failed to fetch https redirect rules")
}
defer get_https_redirect_rules_res.Body.Close()
get_https_redirect_rules_res_body, get_https_redirect_rules_res_body_err := io.ReadAll(get_https_redirect_rules_res.Body)
if get_https_redirect_rules_res_body_err != nil {
return errors.New("failed to read https redirect rules response body")
}
get_https_redirect_rules_res_body_json := map[string]interface{}{}
get_https_redirect_rules_res_body_json_err := json.Unmarshal(get_https_redirect_rules_res_body, &get_https_redirect_rules_res_body_json)
if get_https_redirect_rules_res_body_json_err != nil {
log.Println(get_https_redirect_rules_res_body_json_err)
return errors.New("failed to unmarshal https redirect rules response body")
}
// Find index of HTTPS Redirect Rule
index := -1
get_https_redirect_rules := get_https_redirect_rules_res_body_json["data"].([]interface{})
for _, https_redirect_rule := range get_https_redirect_rules {
https_redirect_rule_item := https_redirect_rule.(map[string]interface{})
if https_redirect_rule_item["cond_test"] == `{ hdr(host) -i `+strings.TrimSpace(match_domain)+` } !letsencrypt-acl` {
index = int(https_redirect_rule_item["index"].(float64))
break
}
}
// Delete HTTPS Redirect Rule
if index != -1 {
delete_https_redirect_rule_request_query_params := QueryParameters{}
delete_https_redirect_rule_request_query_params.add("transaction_id", transaction_id)
delete_https_redirect_rule_request_query_params.add("parent_name", "fe_https")
delete_https_redirect_rule_request_query_params.add("parent_type", "frontend")
// Send request
delete_https_redirect_rule_res, delete_https_redirect_rule := s.deleteRequest("/services/haproxy/configuration/http_request_rules/"+strconv.Itoa(index), delete_https_redirect_rule_request_query_params)
if delete_https_redirect_rule != nil || !isValidStatusCode(delete_https_redirect_rule_res.StatusCode) {
return errors.New("failed to delete https redirect rule")
}
return nil
}
return nil
}
7 changes: 7 additions & 0 deletions swiftwave_service/core/ingress_rule.operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ func (ingressRule *IngressRule) Create(ctx context.Context, db gorm.DB, restrict
return errors.New("there is ingress rule with same port")
}
}
// check if there is no redirect rule with same domain and port
if (ingressRule.Protocol == HTTPProtocol && ingressRule.Port == 80) || ingressRule.Protocol == HTTPSProtocol {
isRedirectRuleExist := db.Where("domain_id = ? AND protocol = ?", ingressRule.DomainID, ingressRule.Protocol).First(&RedirectRule{}).RowsAffected > 0
if isRedirectRuleExist {
return errors.New("there is redirect rule with same domain and port")
}
}

// create record
tx := db.Create(&ingressRule)
Expand Down
2 changes: 1 addition & 1 deletion swiftwave_service/core/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ type IngressRule struct {
type RedirectRule struct {
ID uint `json:"id" gorm:"primaryKey"`
DomainID uint `json:"domainID"`
Port uint `json:"port"`
Protocol ProtocolType `json:"protocol"`
RedirectURL string `json:"redirectURL"`
Status RedirectRuleStatus `json:"status"`
CreatedAt time.Time `json:"createdAt"`
Expand Down
19 changes: 16 additions & 3 deletions swiftwave_service/core/redirect_rule.oprations.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,25 @@ func (redirectRule *RedirectRule) Create(ctx context.Context, db gorm.DB) error
return err
}
// verify if there is no ingress rule with same domain and port
isIngressRuleExist := db.Where("domain_id = ? AND port = ?", redirectRule.DomainID, redirectRule.Port).First(&IngressRule{}).RowsAffected > 0
if redirectRule.Protocol != HTTPProtocol && redirectRule.Protocol != HTTPSProtocol {
return errors.New("invalid protocol")
}
var isIngressRuleExist bool
/*
* For redirect rule with HTTP protocol, port will be anyhow 80
* For redirect rule with HTTPS protocol, port will be anyhow 443
* So, we can check if there is any ingress rule with same domain and port
*/
if redirectRule.Protocol == HTTPProtocol {
isIngressRuleExist = db.Where("domain_id = ? AND protocol = ? AND port = ?", redirectRule.DomainID, redirectRule.Protocol, 80).First(&IngressRule{}).RowsAffected > 0
} else if redirectRule.Protocol == HTTPSProtocol {
isIngressRuleExist = db.Where("domain_id = ? AND protocol = ? AND port = ?", redirectRule.DomainID, redirectRule.Protocol, 443).First(&IngressRule{}).RowsAffected > 0
}
if isIngressRuleExist {
return errors.New("there is ingress rule with same domain and port")
}
// verify if there is no redirect rule with same domain and port
isRedirectRuleExist := db.Where("domain_id = ? AND port = ?", redirectRule.DomainID, redirectRule.Port).First(&RedirectRule{}).RowsAffected > 0
// verify if there is no redirect rule with same domain and protocl
isRedirectRuleExist := db.Where("domain_id = ? AND protocol = ?", redirectRule.DomainID, redirectRule.Protocol).First(&RedirectRule{}).RowsAffected > 0
if isRedirectRuleExist {
return errors.New("there is redirect rule with same domain and port")
}
Expand Down
74 changes: 1 addition & 73 deletions swiftwave_service/graphql/generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions swiftwave_service/graphql/graphql_object_mapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ func ingressRuleToGraphqlObject(record *core.IngressRule) *model.IngressRule {
func redirectRuleInputToDatabaseObject(record *model.RedirectRuleInput) *core.RedirectRule {
return &core.RedirectRule{
DomainID: record.DomainID,
Port: record.Port,
Protocol: core.ProtocolType(record.Protocol),
RedirectURL: record.RedirectURL,
Status: core.RedirectRuleStatusPending,
CreatedAt: time.Now(),
Expand All @@ -284,7 +284,7 @@ func redirectRuleToGraphqlObject(record *core.RedirectRule) *model.RedirectRule
return &model.RedirectRule{
ID: record.ID,
DomainID: record.DomainID,
Port: record.Port,
Protocol: model.ProtocolType(record.Protocol),
RedirectURL: record.RedirectURL,
Status: model.RedirectRuleStatus(record.Status),
CreatedAt: record.CreatedAt,
Expand Down
2 changes: 0 additions & 2 deletions swiftwave_service/graphql/model/models_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 0 additions & 4 deletions swiftwave_service/graphql/redirect_rule.resolvers.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions swiftwave_service/graphql/schema/redirect_rule.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ enum RedirectRuleStatus {
input RedirectRuleInput {
domainId: Uint!
protocol: ProtocolType!
port: Uint!
redirectURL: String!
}

Expand All @@ -17,7 +16,6 @@ type RedirectRule {
domainId: Uint!
domain: Domain!
protocol: ProtocolType!
port: Uint!
redirectURL: String!
status: RedirectRuleStatus!
createdAt: Time!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,12 @@ func (m Manager) RedirectRuleApply(request RedirectRuleApplyRequest, ctx context
if err != nil {
return err
}
// TODO add support for https and custom tcp port
// add redirect
err = m.ServiceManager.HaproxyManager.AddHTTPRedirectRule(haproxyTransactionId, domain.Name, redirectRule.RedirectURL)
if redirectRule.Protocol == core.HTTPProtocol {
err = m.ServiceManager.HaproxyManager.AddHTTPRedirectRule(haproxyTransactionId, domain.Name, redirectRule.RedirectURL)
} else {
err = m.ServiceManager.HaproxyManager.AddHTTPSRedirectRule(haproxyTransactionId, domain.Name, redirectRule.RedirectURL)
}
if err != nil {
// set status as failed and exit
_ = redirectRule.UpdateStatus(ctx, dbWithoutTx, core.RedirectRuleStatusFailed)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,14 @@ func (m Manager) RedirectRuleDelete(request RedirectRuleDeleteRequest, ctx conte
return err
}
// delete redirect rule
err = m.ServiceManager.HaproxyManager.DeleteHTTPRedirectRule(haproxyTransactionId, domain.Name)
if redirectRule.Protocol == core.HTTPProtocol {
err = m.ServiceManager.HaproxyManager.DeleteHTTPRedirectRule(haproxyTransactionId, domain.Name)
} else if redirectRule.Protocol == core.HTTPSProtocol {
err = m.ServiceManager.HaproxyManager.DeleteHTTPSRedirectRule(haproxyTransactionId, domain.Name)
} else {
// invalid protocol
return nil
}
if err != nil {
// set status as failed and exit
// because `DeleteHTTPRedirectRule` can fail only if haproxy not working
Expand Down