MEDIUM: lint: resolving linting and static-check errors

v2.2
Dario Tranchitella 3 years ago
parent a85d5bd2e0
commit 9b637111d3
  1. 14
      client_interface.go
  2. 9
      configuration/acl_test.go
  3. 12
      configuration/backend_test.go
  4. 38
      configuration/configuration.go
  5. 28
      configuration/configuration_test.go
  6. 2
      configuration/defaults.go
  7. 6
      configuration/defaults_test.go
  8. 9
      configuration/filter_test.go
  9. 7
      configuration/frontend_test.go
  10. 7
      configuration/global.go
  11. 5
      configuration/http_request_rule.go
  12. 66
      configuration/http_request_rule_test.go
  13. 41
      configuration/http_response_rule_test.go
  14. 9
      configuration/log_target_test.go
  15. 7
      configuration/peer_section_test.go
  16. 12
      configuration/raw.go
  17. 13
      configuration/resolver.go
  18. 7
      configuration/resolver_test.go
  19. 9
      configuration/server.go
  20. 7
      configuration/server_switching_rule_test.go
  21. 31
      configuration/service.go
  22. 37
      configuration/service_test.go
  23. 9
      configuration/site.go
  24. 14
      configuration/site_test.go
  25. 15
      configuration/stick_rule_test.go
  26. 2
      configuration/tcp_request_rule.go
  27. 15
      configuration/tcp_request_rule_test.go
  28. 9
      configuration/tcp_response_rule_test.go
  29. 25
      configuration/transaction.go
  30. 2
      configuration/version_test.go
  31. 3
      runtime/acls.go
  32. 2
      runtime/frontends.go
  33. 2
      runtime/info.go
  34. 14
      runtime/maps.go
  35. 86
      runtime/runtime_client.go
  36. 6
      runtime/runtime_const.go
  37. 77
      runtime/runtime_single_client.go
  38. 30
      runtime/servers.go
  39. 3
      runtime/stats.go
  40. 6
      runtime/stick_tables.go
  41. 64
      runtimeclient_interface.go

@ -78,13 +78,13 @@ type IConfigurationClient interface {
GetParserTransactions() models.Transactions
// GetParser returns a parser for given transactionID, if transactionID is "", it returns "master" parser
GetParser(transactionID string) (*parser.Parser, error)
//AddParser adds parser to parser map
// AddParser adds parser to parser map
AddParser(transactionID string) error
//DeleteParser deletes parser from parsers map
// DeleteParser deletes parser from parsers map
DeleteParser(transactionID string) error
//CommitParser commits transaction parser, deletes it from parsers map, and replaces master Parser
// CommitParser commits transaction parser, deletes it from parsers map, and replaces master Parser
CommitParser(transactionID string) error
//InitTransactionParsers checks transactions and initializes parsers map with transactions in_progress
// InitTransactionParsers checks transactions and initializes parsers map with transactions in_progress
InitTransactionParsers() error
// GetVersion returns configuration file version
GetVersion(transactionID string) (int64, error)
@ -272,10 +272,10 @@ type IConfigurationClient interface {
// EditServerSwitchingRule edits a server switching rule in configuration. One of version or transactionID is
// mandatory. Returns error on fail, nil on success.
EditServerSwitchingRule(id int64, backend string, data *models.ServerSwitchingRule, transactionID string, version int64) error
//NewService creates and returns a new Service instance.
//name indicates the name of the service and only one Service instance with the given name can be created.
// NewService creates and returns a new Service instance.
// name indicates the name of the service and only one Service instance with the given name can be created.
NewService(name string, scaling configuration.ScalingParams) (*configuration.Service, error)
//DeleteService removes the Service instance specified by name from the client.
// DeleteService removes the Service instance specified by name from the client.
DeleteService(name string)
// GetSites returns configuration version and an array of
// configured sites. Returns error on fail.

@ -38,7 +38,8 @@ func TestGetACLs(t *testing.T) {
}
for _, r := range acls {
if *r.Index == 0 {
switch *r.Index {
case 0:
if r.ACLName != "invalid_src" {
t.Errorf("%v: ACLName not invalid_src: %v", *r.Index, r.ACLName)
}
@ -48,7 +49,7 @@ func TestGetACLs(t *testing.T) {
if r.Criterion != "src" {
t.Errorf("%v: Criterion not src: %v", *r.Index, r.Criterion)
}
} else if *r.Index == 1 {
case 1:
if r.ACLName != "invalid_src" {
t.Errorf("%v: ACLName not invalid_src: %v", *r.Index, r.ACLName)
}
@ -58,7 +59,7 @@ func TestGetACLs(t *testing.T) {
if r.Criterion != "src_port" {
t.Errorf("%v: Criterion not src_port: %v", *r.Index, r.Criterion)
}
} else if *r.Index == 2 {
case 2:
if r.ACLName != "local_dst" {
t.Errorf("%v: ACLName not invalid_src: %v", *r.Index, r.ACLName)
}
@ -68,7 +69,7 @@ func TestGetACLs(t *testing.T) {
if r.Criterion != "hdr(host)" {
t.Errorf("%v: Criterion not hdr(host): %v", *r.Index, r.Criterion)
}
} else {
default:
t.Errorf("Expext only acl 1, 2 or 3, %v found", *r.Index)
}
}

@ -384,12 +384,11 @@ func TestCreateEditDeleteBackend(t *testing.T) {
err = client.DeleteBackend("created", "", 999999999)
if err != nil {
switch err.(type) {
case *ConfError:
if err.(*ConfError).Code() != ErrVersionMismatch {
if confErr, ok := err.(*ConfError); ok {
if confErr.Code() != ErrVersionMismatch {
t.Error("Should throw ErrVersionMismatch error")
}
default:
} else {
t.Error("Should throw ErrVersionMismatch error")
}
}
@ -572,8 +571,5 @@ func compareBackends(x, y *models.Backend, t *testing.T) bool {
x.PgsqlCheckParams = nil
y.PgsqlCheckParams = nil
if !reflect.DeepEqual(x, y) {
return false
}
return true
return reflect.DeepEqual(x, y)
}

@ -37,13 +37,13 @@ import (
)
const (
//DefaultConfigurationFile sane default for path to haproxy configuration file
// DefaultConfigurationFile sane default for path to haproxy configuration file
DefaultConfigurationFile string = "/etc/haproxy/haproxy.cfg"
//DefaultHaproxy sane default for path to haproxy executable
// DefaultHaproxy sane default for path to haproxy executable
DefaultHaproxy string = "/usr/sbin/haproxy"
//DefaultUseValidation sane default using validation in client native
// DefaultUseValidation sane default using validation in client native
DefaultUseValidation bool = true
//DefaultPersistentTransactions sane default using persistent transactions in client native
// DefaultPersistentTransactions sane default using persistent transactions in client native
DefaultPersistentTransactions bool = true
// DefaultTransactionDir sane default for path for transactions
DefaultTransactionDir string = "/etc/haproxy/transactions"
@ -114,6 +114,7 @@ func (c *Client) Init(options ClientParams) error {
options.Haproxy = DefaultHaproxy
}
// #nosec G204
if err := exec.Command(options.Haproxy, "-v").Run(); err != nil {
return NewConfError(ErrCannotFindHAProxy, fmt.Sprintf("path to HAProxy binary not valid: %s", c.Haproxy))
}
@ -174,7 +175,7 @@ func (c *Client) GetParser(transactionID string) (*parser.Parser, error) {
return p, nil
}
//AddParser adds parser to parser map
// AddParser adds parser to parser map
func (c *Client) AddParser(transactionID string) error {
if transactionID == "" {
return NewConfError(ErrValidationError, "Not a valid transaction")
@ -206,7 +207,7 @@ func (c *Client) AddParser(transactionID string) error {
return nil
}
//DeleteParser deletes parser from parsers map
// DeleteParser deletes parser from parsers map
func (c *Client) DeleteParser(transactionID string) error {
if transactionID == "" {
return NewConfError(ErrValidationError, "Not a valid transaction")
@ -219,7 +220,7 @@ func (c *Client) DeleteParser(transactionID string) error {
return nil
}
//CommitParser commits transaction parser, deletes it from parsers map, and replaces master Parser
// CommitParser commits transaction parser, deletes it from parsers map, and replaces master Parser
func (c *Client) CommitParser(transactionID string) error {
if transactionID == "" {
return NewConfError(ErrValidationError, "Not a valid transaction")
@ -233,7 +234,7 @@ func (c *Client) CommitParser(transactionID string) error {
return nil
}
//InitTransactionParsers checks transactions and initializes parsers map with transactions in_progress
// InitTransactionParsers checks transactions and initializes parsers map with transactions in_progress
func (c *Client) InitTransactionParsers() error {
transactions, err := c.GetTransactions("in_progress")
if err != nil {
@ -278,7 +279,7 @@ func (c *Client) getVersion(transactionID string) (int64, error) {
func (c *Client) IncrementVersion() error {
data, _ := c.Parser.Get(parser.Comments, parser.CommentsSectionName, "# _version", true)
ver, _ := data.(*types.ConfigVersion)
ver.Value = ver.Value + 1
ver.Value++
if err := c.Parser.Save(c.ConfigurationFile); err != nil {
return NewConfError(ErrCannotSetVersion, fmt.Sprintf("Cannot set version: %s", err.Error()))
@ -320,7 +321,7 @@ func (c *Client) GetFailedParserTransactionVersion(transactionID string) (int64,
return ver.Value, nil
}
//ParseSection sets the fields of the section based on the provided parser
// ParseSection sets the fields of the section based on the provided parser
func ParseSection(object interface{}, section parser.Section, pName string, p *parser.Parser) error {
sp := &SectionParser{
Object: object,
@ -331,7 +332,7 @@ func ParseSection(object interface{}, section parser.Section, pName string, p *p
return sp.Parse()
}
//SectionParser is used set fields of a section based on the provided parser
// SectionParser is used set fields of a section based on the provided parser
type SectionParser struct {
Object interface{}
Section parser.Section
@ -339,7 +340,7 @@ type SectionParser struct {
Parser *parser.Parser
}
//Parse parses the sections fields and sets their values with the data from the parser
// Parse parses the sections fields and sets their values with the data from the parser
func (s *SectionParser) Parse() error {
objValue := reflect.ValueOf(s.Object).Elem()
for i := 0; i < objValue.NumField(); i++ {
@ -937,9 +938,8 @@ func (s *SectionParser) defaultServer() interface{} {
}
}
}
return dServer
}
return nil
return dServer
}
func (s *SectionParser) errorFiles() interface{} {
@ -1168,7 +1168,7 @@ func (s *SectionParser) monitorFail() interface{} {
return nil
}
//SectionObject represents a configuration section
// SectionObject represents a configuration section
type SectionObject struct {
Object interface{}
Section parser.Section
@ -1176,7 +1176,7 @@ type SectionObject struct {
Parser *parser.Parser
}
//CreateEditSection creates or updates a section in the parser based on the provided object
// CreateEditSection creates or updates a section in the parser based on the provided object
func CreateEditSection(object interface{}, section parser.Section, pName string, p *parser.Parser) error {
so := SectionObject{
Object: object,
@ -1187,7 +1187,7 @@ func CreateEditSection(object interface{}, section parser.Section, pName string,
return so.CreateEditSection()
}
//CreateEditSection creates or updates a section in the parser based on the provided object
// CreateEditSection creates or updates a section in the parser based on the provided object
func (s *SectionObject) CreateEditSection() error {
objValue := reflect.ValueOf(s.Object).Elem()
for i := 0; i < objValue.NumField(); i++ {
@ -1482,8 +1482,8 @@ func (s *SectionObject) httpConnectionMode(field reflect.Value) error {
if err := s.set("option http-keep-alive", nil); err != nil {
return err
}
//Deprecated, delete if exists
s.set("option forceclose", nil)
// Deprecated, delete if exists
_ = s.set("option forceclose", nil)
if !valueIsNil(field) {
pName := fmt.Sprintf("option %v", field.String())

@ -241,20 +241,24 @@ var (
)
func TestMain(m *testing.M) {
err := prepareTestFile(testConf, testPath)
if err != nil {
fmt.Println("Could not prepare tests")
os.Exit(1)
}
defer deleteTestFile(testPath)
client, err = prepareClient(testPath)
if err != nil {
fmt.Println("Could not prepare client:", err.Error())
os.Exit(1)
}
os.Exit(func() int {
var err error
if err = prepareTestFile(testConf, testPath); err != nil {
fmt.Println("Could not prepare tests")
return 1
}
defer func() { _ = deleteTestFile(testPath) }()
client, err = prepareClient(testPath)
if err != nil {
fmt.Println("Could not prepare client:", err.Error())
return 1
}
os.Exit(m.Run())
return m.Run()
}())
}
func prepareTestFile(conf string, path string) error {

@ -35,7 +35,7 @@ func (c *Client) GetDefaultsConfiguration(transactionID string) (int64, *models.
}
d := &models.Defaults{}
ParseSection(d, parser.Defaults, parser.DefaultSectionName, p)
_ = ParseSection(d, parser.Defaults, parser.DefaultSectionName, p)
return v, d, nil
}

@ -107,9 +107,11 @@ func TestGetDefaults(t *testing.T) {
}
if d.ExternalCheck != "enabled" {
t.Errorf("ExternalCheck not enabled: %v", d.ExternalCheck)
} else if d.ExternalCheckPath != "/bin" {
}
if d.ExternalCheckPath != "/bin" {
t.Errorf("ExternalCheckPath not /bin: %v", d.ExternalCheckPath)
} else if d.ExternalCheckCommand != "/bin/true" {
}
if d.ExternalCheckCommand != "/bin/true" {
t.Errorf("ExternalCheckCommand not /bin/true: %v", d.ExternalCheckCommand)
}
}

@ -38,7 +38,8 @@ func TestGetFilters(t *testing.T) {
}
for _, f := range filters {
if *f.Index == 0 {
switch *f.Index {
case 0:
if f.Type != "trace" {
t.Errorf("%v: Type not trace: %v", *f.Index, f.Type)
}
@ -51,11 +52,11 @@ func TestGetFilters(t *testing.T) {
if f.TraceHexdump != true {
t.Errorf("%v: TraceHexdump not true: %v", *f.Index, f.TraceHexdump)
}
} else if *f.Index == 1 {
case 1:
if f.Type != "compression" {
t.Errorf("%v: Type not compression: %v", *f.Index, f.Type)
}
} else if *f.Index == 2 {
case 2:
if f.Type != "trace" {
t.Errorf("%v: Type not trace: %v", *f.Index, f.Type)
}
@ -65,7 +66,7 @@ func TestGetFilters(t *testing.T) {
if f.TraceRndForwarding != true {
t.Errorf("%v: TraceRndForwarding not true: %v", *f.Index, f.TraceRndForwarding)
}
} else {
default:
t.Errorf("Expext only filter 1, 2 or 3, %v found", *f.Index)
}
}

@ -242,12 +242,11 @@ func TestCreateEditDeleteFrontend(t *testing.T) {
err = client.DeleteFrontend("created", "", 999999)
if err != nil {
switch err.(type) {
case *ConfError:
if err.(*ConfError).Code() != ErrVersionMismatch {
if confErr, ok := err.(*ConfError); ok {
if confErr.Code() != ErrVersionMismatch {
t.Error("Should throw ErrVersionMismatch error")
}
default:
} else {
t.Error("Should throw ErrVersionMismatch error")
}
}

@ -149,11 +149,12 @@ func ParseGlobalSection(p *parser.Parser) (*models.Global, error) {
rAPI.ExposeFdListeners = true
}
case *params.BindOptionValue:
if v.Name == "level" {
switch v.Name {
case "level":
rAPI.Level = v.Value
} else if v.Name == "mode" {
case "mode":
rAPI.Mode = v.Value
} else if v.Name == "process" {
case "process":
rAPI.Process = v.Value
}
}

@ -168,7 +168,7 @@ func (c *Client) EditHTTPRequestRule(id int64, parentType string, parentName str
section = parser.Frontends
}
if _, err := p.GetOne(section, parentName, "http-request", int(id)); err != nil {
if _, err = p.GetOne(section, parentName, "http-request", int(id)); err != nil {
return c.HandleError(strconv.FormatInt(id, 10), parentType, parentName, t, transactionID == "", err)
}
@ -226,7 +226,8 @@ func ParseHTTPRequestRule(f types.HTTPAction) (rule *models.HTTPRequestRule, err
}
case *actions.Deny:
var denyPtr *int64
if ds, err := strconv.ParseInt(v.DenyStatus, 10, 64); err == nil {
var ds int64
if ds, err = strconv.ParseInt(v.DenyStatus, 10, 64); err == nil {
denyPtr = &ds
}
rule = &models.HTTPRequestRule{

@ -38,7 +38,8 @@ func TestGetHTTPRequestRules(t *testing.T) {
}
for _, r := range hRules {
if *r.Index == 0 {
switch *r.Index {
case 0:
if r.Type != "allow" {
t.Errorf("%v: Type not allow: %v", *r.Index, r.Type)
}
@ -48,7 +49,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.CondTest != "src 192.168.0.0/16" {
t.Errorf("%v: CondTest not src 192.168.0.0/16: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 1 {
case 1:
if r.Type != "set-header" {
t.Errorf("%v: Type not set-header: %v", *r.Index, r.Type)
}
@ -58,7 +59,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.HdrFormat != "%[ssl_fc]" {
t.Errorf("%v: HdrFormat not [ssl_fc]: %v", *r.Index, r.HdrFormat)
}
} else if *r.Index == 2 {
case 2:
if r.Type != "set-var" {
t.Errorf("%v: Type not set-var: %v", *r.Index, r.Type)
}
@ -71,7 +72,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.VarExpr != "req.fhdr(user-agent),lower" {
t.Errorf("%v: VarPattern not req.fhdr(user-agent),lower: %v", *r.Index, r.VarExpr)
}
} else if *r.Index == 3 {
case 3:
if r.Type != "set-map" {
t.Errorf("%v: Type not set-map: %v", *r.Index, r.Type)
}
@ -84,7 +85,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.MapValuefmt != "%[req.hdr(X-Value)]" {
t.Errorf("%v: MapValuefmt not %%[req.hdr(X-Value)]: %v", *r.Index, r.MapValuefmt)
}
} else if *r.Index == 4 {
case 4:
if r.Type != "del-map" {
t.Errorf("%v: Type not del-map: %v", *r.Index, r.Type)
}
@ -100,7 +101,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 5 {
case 5:
if r.Type != "cache-use" {
t.Errorf("%v: Type not cache-use: %v", *r.Index, r.Type)
}
@ -113,7 +114,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 6 {
case 6:
if r.Type != "disable-l7-retry" {
t.Errorf("%v: Type not disable-l7-retry: %v", *r.Index, r.Type)
}
@ -123,7 +124,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 7 {
case 7:
if r.Type != "early-hint" {
t.Errorf("%v: Type not early-hint: %v", *r.Index, r.Type)
}
@ -139,7 +140,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 8 {
case 8:
if r.Type != "replace-uri" {
t.Errorf("%v: Type not replace-uri: %v", *r.Index, r.Type)
}
@ -155,7 +156,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 9 {
case 9:
if r.Type != "sc-inc-gpc0" {
t.Errorf("%v: Type not sc-inc-gpc0: %v", *r.Index, r.Type)
}
@ -168,7 +169,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 10 {
case 10:
if r.Type != "sc-inc-gpc1" {
t.Errorf("%v: Type not sc-inc-gpc1: %v", *r.Index, r.Type)
}
@ -181,7 +182,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 11 {
case 11:
if r.Type != "do-resolve" {
t.Errorf("%v: Type not do-resolve: %v", *r.Index, r.Type)
}
@ -197,7 +198,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.Expr != "hdr(Host),lower" {
t.Errorf("%v: Expr not hdr(Host),lower: %v", *r.Index, r.Expr)
}
} else if *r.Index == 12 {
case 12:
if r.Type != "sc-set-gpt0" {
t.Errorf("%v: Type not sc-set-gpt0: %v", *r.Index, r.Type)
}
@ -216,7 +217,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 13 {
case 13:
if r.Type != "sc-set-gpt0" {
t.Errorf("%v: Type not sc-set-gpt0: %v", *r.Index, r.Type)
}
@ -239,7 +240,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 14 {
case 14:
if r.Type != "set-mark" {
t.Errorf("%v: Type not set-mark: %v", *r.Index, r.Type)
}
@ -252,7 +253,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 15 {
case 15:
if r.Type != "set-nice" {
t.Errorf("%v: Type not set-nice: %v", *r.Index, r.Type)
}
@ -265,7 +266,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 16 {
case 16:
if r.Type != "set-method" {
t.Errorf("%v: Type not set-method: %v", *r.Index, r.Type)
}
@ -278,7 +279,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 17 {
case 17:
if r.Type != "set-priority-class" {
t.Errorf("%v: Type not set-priority-class: %v", *r.Index, r.Type)
}
@ -291,7 +292,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 18 {
case 18:
if r.Type != "set-priority-offset" {
t.Errorf("%v: Type not set-priority-offset: %v", *r.Index, r.Type)
}
@ -304,7 +305,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 19 {
case 19:
if r.Type != "set-src" {
t.Errorf("%v: Type not set-src: %v", *r.Index, r.Type)
}
@ -317,7 +318,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 20 {
case 20:
if r.Type != "set-src-port" {
t.Errorf("%v: Type not set-src-port: %v", *r.Index, r.Type)
}
@ -330,7 +331,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 21 {
case 21:
if r.Type != "wait-for-handshake" {
t.Errorf("%v: Type not wait-for-handshake: %v", *r.Index, r.Type)
}
@ -340,7 +341,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 22 {
case 22:
if r.Type != "set-tos" {
t.Errorf("%v: Type not set-tos: %v", *r.Index, r.Type)
}
@ -353,7 +354,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 23 {
case 23:
if r.Type != "silent-drop" {
t.Errorf("%v: Type not silent-drop: %v", *r.Index, r.Type)
}
@ -363,7 +364,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 24 {
case 24:
if r.Type != "unset-var" {
t.Errorf("%v: Type not unset-var: %v", *r.Index, r.Type)
}
@ -379,7 +380,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 25 {
case 25:
if r.Type != "strict-mode" {
t.Errorf("%v: Type not strict-mode: %v", *r.Index, r.Type)
}
@ -392,7 +393,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 26 {
case 26:
if r.Type != "lua" {
t.Errorf("%v: Type not lua: %v", *r.Index, r.Type)
}
@ -408,7 +409,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 27 {
case 27:
if r.Type != "use-service" {
t.Errorf("%v: Type not use-service: %v", *r.Index, r.Type)
}
@ -421,7 +422,7 @@ func TestGetHTTPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else {
default:
t.Errorf("Expext only http-request 0 to 27, %v found", *r.Index)
}
}
@ -435,21 +436,22 @@ func TestGetHTTPRequestRules(t *testing.T) {
}
for _, r := range hRules {
if *r.Index == 0 {
switch *r.Index {
case 0:
if r.Type != "set-dst" {
t.Errorf("%v: Type not set-dst: %v", *r.Index, r.Type)
}
if r.Expr != "hdr(x-dst)" {
t.Errorf("%v: Expr not hdr(x-dst): %v", *r.Index, r.VarExpr)
}
} else if *r.Index == 1 {
case 1:
if r.Type != "set-dst-port" {
t.Errorf("%v: Type not set-dst-port: %v", *r.Index, r.Type)
}
if r.Expr != "int(4000)" {
t.Errorf("%v: Expr not v: %v", *r.Index, r.Expr)
}
} else {
default:
t.Errorf("Expext only http-request 0 to %v, %v found", *r.Index, len(hRules)-1)
}
}

@ -38,7 +38,8 @@ func TestGetHTTPResponseRules(t *testing.T) {
}
for _, r := range hRules {
if *r.Index == 0 {
switch *r.Index {
case 0:
if r.Type != "allow" {
t.Errorf("%v: Type not allow: %v", *r.Index, r.Type)
}
@ -48,7 +49,7 @@ func TestGetHTTPResponseRules(t *testing.T) {
if r.CondTest != "src 192.168.0.0/16" {
t.Errorf("%v: CondTest not src 192.168.0.0/16: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 1 {
case 1:
if r.Type != "set-header" {
t.Errorf("%v: Type not set-header: %v", *r.Index, r.Type)
}
@ -58,7 +59,7 @@ func TestGetHTTPResponseRules(t *testing.T) {
if r.HdrFormat != "%[ssl_fc]" {
t.Errorf("%v: HdrValue not [ssl_fc]: %v", *r.Index, r.HdrFormat)
}
} else if *r.Index == 2 {
case 2:
if r.Type != "set-var" {
t.Errorf("%v: Type not set-var: %v", *r.Index, r.Type)
}
@ -71,7 +72,7 @@ func TestGetHTTPResponseRules(t *testing.T) {
if r.VarExpr != "req.fhdr(user-agent),lower" {
t.Errorf("%v: VarExpr not req.fhdr(user-agent),lower: %v", *r.Index, r.VarExpr)
}
} else if *r.Index == 3 {
case 3:
if r.Type != "set-map" {
t.Errorf("%v: Type not set-map: %v", *r.Index, r.Type)
}
@ -84,7 +85,7 @@ func TestGetHTTPResponseRules(t *testing.T) {
if r.MapValuefmt != "%[res.hdr(X-Value)]" {
t.Errorf("%v: MapValuefmt not %%[res.hdr(X-Value)]: %v", *r.Index, r.MapValuefmt)
}
} else if *r.Index == 4 {
case 4:
if r.Type != "del-map" {
t.Errorf("%v: Type not del-map: %v", *r.Index, r.Type)
}
@ -100,7 +101,7 @@ func TestGetHTTPResponseRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 5 {
case 5:
if r.Type != "sc-inc-gpc0" {
t.Errorf("%v: Type not sc-inc-gpc0: %v", *r.Index, r.Type)
}
@ -113,7 +114,7 @@ func TestGetHTTPResponseRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 6 {
case 6:
if r.Type != "sc-inc-gpc1" {
t.Errorf("%v: Type not sc-inc-gpc1: %v", *r.Index, r.Type)
}
@ -126,7 +127,7 @@ func TestGetHTTPResponseRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 7 {
case 7:
if r.Type != "sc-set-gpt0" {
t.Errorf("%v: Type not sc-set-gpt0: %v", *r.Index, r.Type)
}
@ -145,7 +146,7 @@ func TestGetHTTPResponseRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 8 {
case 8:
if r.Type != "sc-set-gpt0" {
t.Errorf("%v: Type not sc-set-gpt0: %v", *r.Index, r.Type)
}
@ -168,7 +169,7 @@ func TestGetHTTPResponseRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 9 {
case 9:
if r.Type != "set-mark" {
t.Errorf("%v: Type not set-mark: %v", *r.Index, r.Type)
}
@ -181,7 +182,7 @@ func TestGetHTTPResponseRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 10 {
case 10:
if r.Type != "set-nice" {
t.Errorf("%v: Type not set-nice: %v", *r.Index, r.Type)
}
@ -194,7 +195,7 @@ func TestGetHTTPResponseRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 11 {
case 11:
if r.Type != "set-tos" {
t.Errorf("%v: Type not set-tos: %v", *r.Index, r.Type)
}
@ -207,7 +208,7 @@ func TestGetHTTPResponseRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 12 {
case 12:
if r.Type != "silent-drop" {
t.Errorf("%v: Type not silent-drop: %v", *r.Index, r.Type)
}
@ -217,7 +218,7 @@ func TestGetHTTPResponseRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 13 {
case 13:
if r.Type != "unset-var" {
t.Errorf("%v: Type not unset-var: %v", *r.Index, r.Type)
}
@ -233,7 +234,7 @@ func TestGetHTTPResponseRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 14 {
case 14:
if r.Type != "track-sc0" {
t.Errorf("%v: Type not track-sc0: %v", *r.Index, r.Type)
}
@ -249,7 +250,7 @@ func TestGetHTTPResponseRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 15 {
case 15:
if r.Type != "track-sc1" {
t.Errorf("%v: Type not track-sc1: %v", *r.Index, r.Type)
}
@ -265,7 +266,7 @@ func TestGetHTTPResponseRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 16 {
case 16:
if r.Type != "track-sc2" {
t.Errorf("%v: Type not track-sc2: %v", *r.Index, r.Type)
}
@ -281,7 +282,7 @@ func TestGetHTTPResponseRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 17 {
case 17:
if r.Type != "strict-mode" {
t.Errorf("%v: Type not strict-mode: %v", *r.Index, r.Type)
}
@ -294,7 +295,7 @@ func TestGetHTTPResponseRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 18 {
case 18:
if r.Type != "lua" {
t.Errorf("%v: Type not lua: %v", *r.Index, r.Type)
}
@ -310,7 +311,7 @@ func TestGetHTTPResponseRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not FALSE: %v", *r.Index, r.CondTest)
}
} else {
default:
t.Errorf("Expext only http-response 0 to 18, %v found", *r.Index)
}
}

@ -38,15 +38,16 @@ func TestGetLogTargets(t *testing.T) {
}
for _, l := range lTargets {
if *l.Index == 0 {
switch *l.Index {
case 0:
if l.Global != true {
t.Errorf("%v: Global not true: %v", *l.Index, l.Global)
}
} else if *l.Index == 1 {
case 1:
if l.Nolog != true {
t.Errorf("%v: Nolog not true: %v", *l.Index, l.Nolog)
}
} else if *l.Index == 2 {
case 2:
if l.Address != "127.0.0.1:514" {
t.Errorf("%v: Address not 127.0.0.1:514: %v", *l.Index, l.Address)
}
@ -59,7 +60,7 @@ func TestGetLogTargets(t *testing.T) {
if l.Minlevel != "notice" {
t.Errorf("%v: Minlevel not notice: %v", *l.Index, l.Minlevel)
}
} else {
default:
t.Errorf("Expext only log 0, 1, or 2, %v found", *l.Index)
}
}

@ -111,12 +111,11 @@ func TestCreateEditDeletePeerSection(t *testing.T) {
err = client.DeletePeerSection("testcluster", "", 999999)
if err != nil {
switch err.(type) {
case *ConfError:
if err.(*ConfError).Code() != ErrVersionMismatch {
if confErr, ok := err.(*ConfError); ok {
if confErr.Code() != ErrVersionMismatch {
t.Error("Should throw ErrVersionMismatch error")
}
default:
} else {
t.Error("Should throw ErrVersionMismatch error")
}
}

@ -33,7 +33,8 @@ func (c *Client) GetRawConfiguration(transactionID string, version int64) (int64
var err error
if transactionID != "" && version != 0 {
return 0, "", NewConfError(ErrBothVersionTransaction, "Both version and transactionID specified, specify only one")
} else if transactionID != "" {
}
if transactionID != "" {
config, err = c.GetTransactionFile(transactionID)
if err != nil {
return 0, "", err
@ -125,18 +126,18 @@ func (c *Client) PostRawConfiguration(config *string, version int64, skipVersion
}
// Write the transaction file directly
tmp, err := os.OpenFile(tFile, os.O_RDWR|os.O_TRUNC, 0777)
defer tmp.Close()
defer func() { _ = tmp.Close() }()
if err != nil {
return NewConfError(ErrCannotReadConfFile, err.Error())
}
w := bufio.NewWriter(tmp)
if !skipVersionCheck {
w.WriteString(fmt.Sprintf("# _version=%v\n%v", version, *config))
_, _ = w.WriteString(fmt.Sprintf("# _version=%v\n%v", version, *config))
} else {
w.WriteString(*config)
_, _ = w.WriteString(*config)
}
w.Flush()
_ = w.Flush()
// Load the data into the transaction parser
p, err := c.GetParser(t)
@ -157,6 +158,7 @@ func (c *Client) PostRawConfiguration(config *string, version int64, skipVersion
}
func (c *Client) validateConfigFile(confFile string) error {
// #nosec G204
cmd := exec.Command(c.Haproxy)
cmd.Args = append(cmd.Args, "-c")

@ -19,12 +19,13 @@ import (
"fmt"
"strconv"
strfmt "github.com/go-openapi/strfmt"
"github.com/haproxytech/client-native/v2/misc"
"github.com/go-openapi/strfmt"
parser "github.com/haproxytech/config-parser/v3"
"github.com/haproxytech/config-parser/v3/common"
"github.com/haproxytech/config-parser/v3/types"
"github.com/haproxytech/models/v2"
"github.com/haproxytech/client-native/v2/misc"
)
// GetResolvers returns configuration version and an array of
@ -334,10 +335,8 @@ func SerializeResolverSection(p *parser.Parser, data *models.Resolver) error {
if err = p.Set(parser.Resolvers, data.Name, "parse-resolv-conf", b); err != nil {
return err
}
} else {
if err = p.Set(parser.Resolvers, data.Name, "parse-resolv-conf", nil); err != nil {
return err
}
} else if err = p.Set(parser.Resolvers, data.Name, "parse-resolv-conf", nil); err != nil {
return err
}
if data.ResolveRetries == 0 {
if err = p.Set(parser.Resolvers, data.Name, "resolve_retries", nil); err != nil {
@ -365,7 +364,7 @@ func SerializeResolverSection(p *parser.Parser, data *models.Resolver) error {
}
} else {
timeout := types.SimpleTimeout{Value: strconv.FormatInt(data.TimeoutRetry, 10)}
if err := p.Set(parser.Resolvers, data.Name, "timeout retry", timeout); err != nil {
if err = p.Set(parser.Resolvers, data.Name, "timeout retry", timeout); err != nil {
return err
}
}

@ -123,12 +123,11 @@ func TestCreateEditDeleteResolver(t *testing.T) {
err = client.DeleteResolver("created_resolver", "", 999999)
if err != nil {
switch err.(type) {
case *ConfError:
if err.(*ConfError).Code() != ErrVersionMismatch {
if confErr, ok := err.(*ConfError); ok {
if confErr.Code() != ErrVersionMismatch {
t.Error("Should throw ErrVersionMismatch error")
}
default:
} else {
t.Error("Should throw ErrVersionMismatch error")
}
}

@ -183,9 +183,12 @@ func ParseServer(ondiskServer types.Server) *models.Server {
Name: ondiskServer.Name,
}
addSlice := strings.Split(ondiskServer.Address, ":")
if len(addSlice) == 0 {
switch len(addSlice) {
case 0:
return nil
} else if len(addSlice) > 1 {
case 1:
s.Address = addSlice[0]
default:
s.Address = addSlice[0]
if addSlice[1] != "" {
p, err := strconv.ParseInt(addSlice[1], 10, 64)
@ -193,8 +196,6 @@ func ParseServer(ondiskServer types.Server) *models.Server {
s.Port = &p
}
}
} else if len(addSlice) > 0 {
s.Address = addSlice[0]
}
for _, p := range ondiskServer.Params {
switch v := p.(type) {

@ -38,7 +38,8 @@ func TestGetServerSwitchingRules(t *testing.T) {
}
for _, sr := range srvRules {
if *sr.Index == 0 {
switch *sr.Index {
case 0:
if sr.TargetServer != "webserv" {
t.Errorf("%v: TargetServer not webserv: %v", *sr.Index, sr.TargetServer)
}
@ -48,7 +49,7 @@ func TestGetServerSwitchingRules(t *testing.T) {
if sr.CondTest != "TRUE" {
t.Errorf("%v: CondTest not TRUE: %v", *sr.Index, sr.CondTest)
}
} else if *sr.Index == 1 {
case 1:
if sr.TargetServer != "webserv2" {
t.Errorf("%v: TargetServer not webserv2: %v", *sr.Index, sr.TargetServer)
}
@ -58,7 +59,7 @@ func TestGetServerSwitchingRules(t *testing.T) {
if sr.CondTest != "TRUE" {
t.Errorf("%v: CondTest not TRUE: %v", *sr.Index, sr.CondTest)
}
} else {
default:
t.Errorf("Expext only server switching rule 0 or 1, %v found", *sr.Index)
}
}

@ -22,13 +22,13 @@ import (
"github.com/haproxytech/models/v2"
)
//ServiceGrowthTypeLinear indicates linear growth type in ScalingParams.
// ServiceGrowthTypeLinear indicates linear growth type in ScalingParams.
const ServiceGrowthTypeLinear = "linear"
//ServiceGrowthTypeExponential indicates exponential growth type in ScalingParams.
// ServiceGrowthTypeExponential indicates exponential growth type in ScalingParams.
const ServiceGrowthTypeExponential = "exponential"
//ServiceServer contains information for one server in the service.
// ServiceServer contains information for one server in the service.
type ServiceServer struct {
Address string
Port int
@ -42,26 +42,25 @@ type serviceNode struct {
modified bool
}
//Service represents the maping from a discovery service into a configuration backend.
// Service represents the maping from a discovery service into a configuration backend.
type Service struct {
client *Client
name string
nodes []*serviceNode
usedNames map[string]struct{}
transactionID string
backendName string
scaling ScalingParams
}
//ScalingParams defines parameter for dynamic server scaling of the Service backend.
// ScalingParams defines parameter for dynamic server scaling of the Service backend.
type ScalingParams struct {
BaseSlots int
SlotsGrowthType string
SlotsIncrement int
}
//NewService creates and returns a new Service instance.
//name indicates the name of the service and only one Service instance with the given name can be created.
// NewService creates and returns a new Service instance.
// name indicates the name of the service and only one Service instance with the given name can be created.
func (c *Client) NewService(name string, scaling ScalingParams) (*Service, error) {
c.mu.Lock()
defer c.mu.Unlock()
@ -79,14 +78,14 @@ func (c *Client) NewService(name string, scaling ScalingParams) (*Service, error
return service, nil
}
//DeleteService removes the Service instance specified by name from the client.
// DeleteService removes the Service instance specified by name from the client.
func (c *Client) DeleteService(name string) {
c.mu.Lock()
defer c.mu.Unlock()
delete(c.services, name)
}
//Delete removes the service from the client with all the associated configuration resources.
// Delete removes the service from the client with all the associated configuration resources.
func (s *Service) Delete() error {
err := s.client.DeleteBackend(s.name, s.transactionID, 0)
if err != nil {
@ -96,7 +95,7 @@ func (s *Service) Delete() error {
return nil
}
//Init initiates the client by reading the configuration associated with it or created the initial configuration if it does not exist.
// Init initiates the client by reading the configuration associated with it or created the initial configuration if it does not exist.
func (s *Service) Init(transactionID string) (bool, error) {
s.SetTransactionID(transactionID)
newBackend, err := s.createBackend()
@ -109,12 +108,12 @@ func (s *Service) Init(transactionID string) (bool, error) {
return s.loadNodes()
}
//SetTransactionID updates the transaction ID to be used for modifications on the configuration associated with the service.
// SetTransactionID updates the transaction ID to be used for modifications on the configuration associated with the service.
func (s *Service) SetTransactionID(transactionID string) {
s.transactionID = transactionID
}
//UpdateScalingParams updates parameters used for dynamic server scaling of the Service backend
// UpdateScalingParams updates parameters used for dynamic server scaling of the Service backend
func (s *Service) UpdateScalingParams(scaling ScalingParams) error {
s.scaling = scaling
if s.serverCount() < s.scaling.BaseSlots {
@ -123,7 +122,7 @@ func (s *Service) UpdateScalingParams(scaling ScalingParams) error {
return nil
}
//Update updates the backend associated with the server based on the list of servers provided
// Update updates the backend associated with the server based on the list of servers provided
func (s *Service) Update(servers []ServiceServer) (bool, error) {
reload := false
r, err := s.expandNodes(len(servers))
@ -133,7 +132,7 @@ func (s *Service) Update(servers []ServiceServer) (bool, error) {
reload = reload || r
s.markRemovedNodes(servers)
for _, server := range servers {
if err := s.handleNode(server); err != nil {
if err = s.handleNode(server); err != nil {
return false, err
}
}
@ -152,7 +151,7 @@ func (s *Service) Update(servers []ServiceServer) (bool, error) {
return reload, nil
}
//GetServers returns the list of servers as they are currently configured in the services backend
// GetServers returns the list of servers as they are currently configured in the services backend
func (s *Service) GetServers() (models.Servers, error) {
_, servers, err := s.client.GetServers(s.name, s.transactionID)
return servers, err

@ -19,9 +19,10 @@ import (
"fmt"
"testing"
"github.com/haproxytech/client-native/v2/misc"
"github.com/haproxytech/models/v2"
"github.com/stretchr/testify/suite"
"github.com/haproxytech/client-native/v2/misc"
)
const baseSlots = 20
@ -97,7 +98,7 @@ func (s *ServiceInitiationSuite) BeforeTest(suiteName, testName string) {
}
func (s *ServiceInitiationSuite) AfterTest(suiteName, testName string) {
//run Init to set transactionID if test did not run it
// run Init to set transactionID if test did not run it
_, err := s.service.Init(s.transactionID)
s.Nil(err)
err = s.service.Delete()
@ -149,8 +150,8 @@ func (s *ServiceInitiationSuite) TestLoadExistingBackend() {
s.Nil(s.createExistingService(servers))
r, err := s.service.Init(s.transactionID)
//Only existing data for was loaded
//No modifications on the config have been done as the server count matches base slots value so reload should be false
// Only existing data for was loaded
// No modifications on the config have been done as the server count matches base slots value so reload should be false
s.False(r)
s.Nil(err)
cServers, err := s.service.GetServers()
@ -279,10 +280,10 @@ func (s *ServiceUpdateSuit) TestSecondUpdateWithDeletedServer() {
r, err = s.service.Update(servers)
s.True(r)
s.Nil(err)
//When the new server list has less servers than the previous one "holes" can be left
//in the middle of enabled servers.
//In this case server 127.1.1.2 got removed and the last enabled server from the remaining ones
//gets moved into its slot, in this case 127.1.1.4
// When the new server list has less servers than the previous one "holes" can be left
// in the middle of enabled servers.
// In this case server 127.1.1.2 got removed and the last enabled server from the remaining ones
// gets moved into its slot, in this case 127.1.1.4
expected := []ServiceServer{
{Address: "127.1.1.1", Port: 81},
{Address: "127.1.1.4", Port: 84},
@ -312,10 +313,10 @@ func (s *ServiceUpdateSuit) TestSecondUpdateWithNewAndRemovedServers() {
r, err = s.service.Update(servers)
s.True(r)
s.Nil(err)
//Server 127.1.1.3 is the only that will be marked as deleted
//as server 127.1.1.2 reapears at the end of the server list with the same port.
//The first new server will be placed in place of server 127.1.1.3 which is 127.1.1.5.
//The remaining new servers will be added to the end.
// Server 127.1.1.3 is the only that will be marked as deleted
// as server 127.1.1.2 reapears at the end of the server list with the same port.
// The first new server will be placed in place of server 127.1.1.3 which is 127.1.1.5.
// The remaining new servers will be added to the end.
expected := []ServiceServer{
{Address: "127.1.1.1", Port: 81},
{Address: "127.1.1.2", Port: 82},
@ -380,7 +381,7 @@ func (s *ServiceUpdateSuit) generateServers(count int) []ServiceServer {
func (s *ServiceUpdateSuit) TestExponentialUpscaling() {
expectedSlotsCount := baseSlots * 2
//Switch from linear to exponential scaling
// Switch from linear to exponential scaling
err := s.service.UpdateScalingParams(ScalingParams{
BaseSlots: baseSlots,
SlotsGrowthType: ServiceGrowthTypeExponential,
@ -398,11 +399,11 @@ func (s *ServiceUpdateSuit) TestExponentialUpscaling() {
}
func (s *ServiceUpdateSuit) TestLinearDownscaling() {
//First we need to increase the server count to be one at least one threshold above our final expected value
// First we need to increase the server count to be one at least one threshold above our final expected value
upscaleExpectedSlots := baseSlots + 2*slotsIncrement
upscaleServerCount := baseSlots + slotsIncrement + 2
s.scaleServiceAndValidate(upscaleExpectedSlots, upscaleServerCount)
//Now we can update with the expected servers and validate if the service downscaled
// Now we can update with the expected servers and validate if the service downscaled
expectedSlotsCount := baseSlots + slotsIncrement
serverCount := baseSlots + 2
s.scaleServiceAndValidate(expectedSlotsCount, serverCount)
@ -420,18 +421,18 @@ func (s *ServiceUpdateSuit) scaleServiceAndValidate(expectedSlots, serverCount i
}
func (s *ServiceUpdateSuit) TestExponentialDownscaling() {
//Switch from linear to exponential scaling
// Switch from linear to exponential scaling
err := s.service.UpdateScalingParams(ScalingParams{
BaseSlots: baseSlots,
SlotsGrowthType: ServiceGrowthTypeExponential,
SlotsIncrement: slotsIncrement,
})
s.Nil(err)
//First we need to increase the server count to be one at least one threshold above our final expected value
// First we need to increase the server count to be one at least one threshold above our final expected value
upscaleExpectedSlots := baseSlots * 2 * 2
upscaleServerCount := baseSlots*2 + 2
s.scaleServiceAndValidate(upscaleExpectedSlots, upscaleServerCount)
//Now we can update with the expected servers and validate if the service downscaled
// Now we can update with the expected servers and validate if the service downscaled
expectedSlotsCount := baseSlots * 2
serverCount := baseSlots + 2
s.scaleServiceAndValidate(expectedSlotsCount, serverCount)

@ -176,8 +176,7 @@ func (c *Client) EditSite(name string, data *models.Site, transactionID string,
// edit frontend
if !reflect.DeepEqual(data.Service, confS.Service) {
err := c.editService(data.Name, data.Service, t, p)
if err != nil {
if err = c.editService(data.Name, data.Service, t, p); err != nil {
res = append(res, err)
}
// compare listeners
@ -330,8 +329,7 @@ func (c *Client) EditSite(name string, data *models.Site, transactionID string,
// default_bck
if b.UseAs == "conditional" {
// find the correct usefarm and remove it
err := c.removeUseFarm(name, b.Name, t, p)
if err != nil {
if err = c.removeUseFarm(name, b.Name, t, p); err != nil {
res = append(res, err)
}
}
@ -418,7 +416,8 @@ func (c *Client) DeleteSite(name string, transactionID string, version int64) er
continue
}
farmsUsed[f.DefaultBackend] = true
_, ubs, err := c.GetBackendSwitchingRules(f.Name, t)
var ubs models.BackendSwitchingRules
_, ubs, err = c.GetBackendSwitchingRules(f.Name, t)
if err == nil {
for _, ub := range ubs {
farmsUsed[ub.Name] = true

@ -40,7 +40,8 @@ func TestGetSites(t *testing.T) {
}
for _, s := range sites {
if s.Name == "test" {
switch s.Name {
case "test":
if *s.Service.Maxconn != 2000 {
t.Errorf("%v: Maxconn not 2000: %v", s.Name, *s.Service.Maxconn)
}
@ -65,7 +66,8 @@ func TestGetSites(t *testing.T) {
}
}
for _, b := range s.Farms {
if b.Name == "test" {
switch b.Name {
case "test":
if b.UseAs != "default" {
t.Errorf("%v: %v: UseAs not default: %v", s.Name, b.Name, b.UseAs)
}
@ -98,7 +100,7 @@ func TestGetSites(t *testing.T) {
t.Errorf("%v: %v: %v: Weight not 10: %v", s.Name, b.Name, srv.Name, *srv.Weight)
}
}
} else if b.Name == "test_2" {
case "test_2":
if b.UseAs != "conditional" {
t.Errorf("%v: %v: UseAs not conditional: %v", s.Name, b.Name, b.UseAs)
}
@ -120,11 +122,11 @@ func TestGetSites(t *testing.T) {
if len(b.Servers) != 0 {
t.Errorf("%v: %v: Got %v servers, expected 0", s.Name, b.Name, len(b.Servers))
}
} else {
default:
t.Errorf("%v: Expected only test or test_2 backends, %v found", s.Name, b.Name)
}
}
} else if s.Name == "test_2" {
case "test_2":
if *s.Service.Maxconn != 2000 {
t.Errorf("%v: MaxConnections not 2000: %v", s.Name, *s.Service.Maxconn)
}
@ -158,7 +160,7 @@ func TestGetSites(t *testing.T) {
t.Errorf("%v: Expected only test_2 backend, %v found", s.Name, b.Name)
}
}
} else {
default:
t.Errorf("Expected only test or test_2 sites, %v found", s.Name)
}
}

@ -38,7 +38,8 @@ func TestGetStickRules(t *testing.T) {
}
for _, sr := range sRules {
if *sr.Index == 0 {
switch *sr.Index {
case 0:
if sr.Type != "store-request" {
t.Errorf("%v: Type not store-request: %v", *sr.Index, sr.Type)
}
@ -48,7 +49,7 @@ func TestGetStickRules(t *testing.T) {
if sr.Table != "test" {
t.Errorf("%v: Table not test: %v", *sr.Index, sr.Table)
}
} else if *sr.Index == 1 {
case 1:
if sr.Type != "match" {
t.Errorf("%v: Type not match: %v", *sr.Index, sr.Type)
}
@ -58,7 +59,7 @@ func TestGetStickRules(t *testing.T) {
if sr.Table != "test" {
t.Errorf("%v: Table not test: %v", *sr.Index, sr.Table)
}
} else if *sr.Index == 2 {
case 2:
if sr.Type != "on" {
t.Errorf("%v: Type not on: %v", *sr.Index, sr.Type)
}
@ -68,14 +69,14 @@ func TestGetStickRules(t *testing.T) {
if sr.Table != "test" {
t.Errorf("%v: Table not test: %v", *sr.Index, sr.Table)
}
} else if *sr.Index == 3 {
case 3:
if sr.Type != "store-response" {
t.Errorf("%v: Type not matchandstore: %v", *sr.Index, sr.Type)
}
if sr.Pattern != "src" {
t.Errorf("%v: Pattern not src: %v", *sr.Index, sr.Pattern)
}
} else if *sr.Index == 4 {
case 4:
if sr.Type != "store-response" {
t.Errorf("%v: Type not matchandstore: %v", *sr.Index, sr.Type)
}
@ -85,7 +86,7 @@ func TestGetStickRules(t *testing.T) {
if sr.Table != "test_port" {
t.Errorf("%v: Table not test: %v", *sr.Index, sr.Table)
}
} else if *sr.Index == 5 {
case 5:
if sr.Type != "store-response" {
t.Errorf("%v: Type not matchandstore: %v", *sr.Index, sr.Type)
}
@ -101,7 +102,7 @@ func TestGetStickRules(t *testing.T) {
if sr.CondTest != "TRUE" {
t.Errorf("%v: Cond not if: %v", *sr.Index, sr.CondTest)
}
} else {
default:
t.Errorf("Expext only stick rule < 5, %v found", *sr.Index)
}
}

@ -169,7 +169,7 @@ func (c *Client) EditTCPRequestRule(id int64, parentType string, parentName stri
section = parser.Frontends
}
if _, err := p.GetOne(section, parentName, "tcp-request", int(id)); err != nil {
if _, err = p.GetOne(section, parentName, "tcp-request", int(id)); err != nil {
return c.HandleError(strconv.FormatInt(id, 10), parentType, parentName, t, transactionID == "", err)
}

@ -38,7 +38,8 @@ func TestGetTCPRequestRules(t *testing.T) {
}
for _, r := range tRules {
if *r.Index == 0 {
switch *r.Index {
case 0:
if r.Type != "connection" {
t.Errorf("%v: Type not connection: %v", *r.Index, r.Type)
}
@ -51,7 +52,7 @@ func TestGetTCPRequestRules(t *testing.T) {
if r.CondTest != "TRUE" {
t.Errorf("%v: CondTest not src TRUE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 1 {
case 1:
if r.Type != "connection" {
t.Errorf("%v: Type not connection: %v", *r.Index, r.Type)
}
@ -64,7 +65,7 @@ func TestGetTCPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not src FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 2 {
case 2:
if r.Type != "content" {
t.Errorf("%v: Type not content: %v", *r.Index, r.Type)
}
@ -77,7 +78,7 @@ func TestGetTCPRequestRules(t *testing.T) {
if r.CondTest != "TRUE" {
t.Errorf("%v: CondTest not src TRUE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 3 {
case 3:
if r.Type != "content" {
t.Errorf("%v: Type not content: %v", *r.Index, r.Type)
}
@ -90,7 +91,7 @@ func TestGetTCPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not src FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 4 {
case 4:
if r.Type != "connection" {
t.Errorf("%v: Type not connection: %v", *r.Index, r.Type)
}
@ -109,7 +110,7 @@ func TestGetTCPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not src FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 5 {
case 5:
if r.Type != "content" {
t.Errorf("%v: Type not content: %v", *r.Index, r.Type)
}
@ -128,7 +129,7 @@ func TestGetTCPRequestRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not src FALSE: %v", *r.Index, r.CondTest)
}
} else {
default:
t.Errorf("Expext tcp-request 0-5, %v found", *r.Index)
}
}

@ -38,7 +38,8 @@ func TestGetTCPResponseRules(t *testing.T) {
}
for _, r := range tRules {
if *r.Index == 0 {
switch *r.Index {
case 0:
if r.Type != "content" {
t.Errorf("%v: Type not content: %v", *r.Index, r.Type)
}
@ -51,7 +52,7 @@ func TestGetTCPResponseRules(t *testing.T) {
if r.CondTest != "TRUE" {
t.Errorf("%v: CondTest not src TRUE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 1 {
case 1:
if r.Type != "content" {
t.Errorf("%v: Type not content: %v", *r.Index, r.Type)
}
@ -64,7 +65,7 @@ func TestGetTCPResponseRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not src FALSE: %v", *r.Index, r.CondTest)
}
} else if *r.Index == 2 {
case 2:
if r.Type != "content" {
t.Errorf("%v: Type not content: %v", *r.Index, r.Type)
}
@ -83,7 +84,7 @@ func TestGetTCPResponseRules(t *testing.T) {
if r.CondTest != "FALSE" {
t.Errorf("%v: CondTest not src FALSE: %v", *r.Index, r.CondTest)
}
} else {
default:
t.Errorf("Expext only tcp-response 0, 1 or 2, %v found", *r.Index)
}
}

@ -217,8 +217,10 @@ func (t *Transaction) checkTransactionFile(transactionID string) error {
}
var cmd *exec.Cmd
if t.MasterWorker {
// #nosec G204
cmd = exec.Command(t.Haproxy, "-W", "-f", transactionFile, "-c")
} else {
// #nosec G204
cmd = exec.Command(t.Haproxy, "-f", transactionFile, "-c")
}
@ -238,9 +240,11 @@ func (t *Transaction) CheckTransactionOrVersion(transactionID string, version in
tID := ""
if transactionID != "" && version != 0 {
return "", NewConfError(ErrBothVersionTransaction, "both version and transaction specified, specify only one")
} else if transactionID == "" && version == 0 {
}
if transactionID == "" && version == 0 {
return "", NewConfError(ErrNoVersionTransaction, "version or transaction not specified, specify only one")
} else if transactionID != "" {
}
if transactionID != "" {
tID = transactionID
} else {
v, err := t.TransactionClient.GetVersion("")
@ -496,11 +500,11 @@ func (t *Transaction) failTransaction(transactionID string) {
func (t *Transaction) writeFailedTransaction(transactionID, configFile string) {
failedDir := filepath.Join(t.TransactionDir, "failed")
if _, err := os.Stat(failedDir); os.IsNotExist(err) {
os.Mkdir(failedDir, 0755)
_ = os.Mkdir(failedDir, 0755)
}
failedConfigFile := t.getTransactionFileFailed(transactionID)
if err := moveFile(configFile, failedConfigFile); err != nil {
os.Remove(configFile)
_ = os.Remove(configFile)
}
}
@ -568,7 +572,7 @@ func (t *Transaction) SaveData(prsr interface{}, tID string, commitImplicit bool
func (t *Transaction) ErrAndDeleteTransaction(err error, tID string) error {
// Just a safety to not delete the master files by mistake
if tID != "" {
t.DeleteTransaction(tID)
_ = t.DeleteTransaction(tID)
return err
}
return err
@ -576,19 +580,20 @@ func (t *Transaction) ErrAndDeleteTransaction(err error, tID string) error {
func (t *Transaction) HandleError(id, parentType, parentName, transactionID string, implicit bool, err error) error {
var e error
if err == parser_errors.ErrSectionMissing {
switch err {
case parser_errors.ErrSectionMissing:
if parentName != "" {
e = NewConfError(ErrParentDoesNotExist, fmt.Sprintf("%s %s does not exist", parentType, parentName))
} else {
e = NewConfError(ErrObjectDoesNotExist, fmt.Sprintf("Object %s does not exist", id))
}
} else if err == parser_errors.ErrSectionAlreadyExists {
case parser_errors.ErrSectionAlreadyExists:
e = NewConfError(ErrObjectAlreadyExists, fmt.Sprintf("Object %s already exists", id))
} else if err == parser_errors.ErrFetch {
case parser_errors.ErrFetch:
e = NewConfError(ErrObjectDoesNotExist, fmt.Sprintf("Object %v does not exist in %s %s", id, parentType, parentName))
} else if err == parser_errors.ErrIndexOutOfRange {
case parser_errors.ErrIndexOutOfRange:
e = NewConfError(ErrObjectIndexOutOfRange, fmt.Sprintf("Object with id %v in %s %s out of range", id, parentType, parentName))
} else {
default:
e = err
}

@ -72,7 +72,7 @@ global
{
name: "Pass without version",
configurationFile: fNoVersion,
want: 1, //config without version should add `# _version=1`
want: 1, // config without version should add `# _version=1`
wantErr: false,
},
}

@ -5,8 +5,9 @@ import (
"regexp"
"strings"
native_errors "github.com/haproxytech/client-native/v2/errors"
"github.com/haproxytech/models/v2"
native_errors "github.com/haproxytech/client-native/v2/errors"
)
// ShowACLS returns Acl files description from runtime

@ -20,7 +20,7 @@ import (
"strconv"
)
//SetFrontendMaxConn set maxconn for frontend
// SetFrontendMaxConn set maxconn for frontend
func (s *SingleRuntime) SetFrontendMaxConn(frontend string, maxconn int) error {
cmd := fmt.Sprintf("set maxconn frontend %s %s", frontend, strconv.FormatInt(int64(maxconn), 10))
return s.Execute(cmd)

@ -23,7 +23,7 @@ import (
"github.com/haproxytech/models/v2"
)
//GetInfo fetches HAProxy info from runtime API
// GetInfo fetches HAProxy info from runtime API
func (s *SingleRuntime) GetInfo() models.ProcessInfo {
dataStr, err := s.ExecuteRaw("show info typed")
data := models.ProcessInfo{RuntimeAPI: s.socketPath}

@ -157,11 +157,11 @@ func parseMapEntry(line string, hasId bool) *models.MapEntry {
m := &models.MapEntry{}
if hasId {
m.ID = parts[0] //map entries from runtime have ID
m.ID = parts[0] // map entries from runtime have ID
m.Key = parts[1]
m.Value = parts[2]
} else {
m.Key = parts[0] //map entries from file
m.Key = parts[0] // map entries from file
m.Value = parts[1]
}
return m
@ -224,11 +224,11 @@ func (s *SingleRuntime) GetMapEntry(name, id string) (*models.MapEntry, error) {
m.Value = strings.TrimPrefix(strings.TrimSuffix(kv[1], "\""), "\"")
}
}
//safe guard m.Key != id:
//when id doesn't exists in runtime maps,
//but any existing key is substring of id
//get map command returns wrong result(BUG in HAProxy)
//so we need to check it
// safe guard m.Key != id:
// when id doesn't exists in runtime maps,
// but any existing key is substring of id
// get map command returns wrong result(BUG in HAProxy)
// so we need to check it
if m.Key == "" || m.Value == "" || m.Key != id {
return nil, fmt.Errorf("%s %w", id, native_errors.ErrNotFound)
}

@ -30,7 +30,7 @@ import (
"github.com/haproxytech/models/v2"
)
//Client handles multiple HAProxy clients
// Client handles multiple HAProxy clients
type Client struct {
ClientParams
haproxyVersion *HAProxyVersion
@ -56,9 +56,9 @@ func DefaultClient() (*Client, error) {
return c, nil
}
//Init must be given path to runtime socket and nbproc that is not 0 when in master worker mode
// Init must be given path to runtime socket and nbproc that is not 0 when in master worker mode
//
//Deprecated: use InitWithSockets or InitWithMasterSocket instead
// Deprecated: use InitWithSockets or InitWithMasterSocket instead
func (c *Client) Init(socketPath []string, masterSocketPath string, nbproc int) error {
c.runtimes = make([]SingleRuntime, len(socketPath))
for index, path := range socketPath {
@ -117,7 +117,7 @@ func (c *Client) InitWithMasterSocket(masterSocketPath string, nbproc int) error
return nil
}
//GetStats returns stats from the socket
// GetStats returns stats from the socket
func (c *Client) GetStats() models.NativeStats {
result := make(models.NativeStats, len(c.runtimes))
for index, runtime := range c.runtimes {
@ -126,7 +126,7 @@ func (c *Client) GetStats() models.NativeStats {
return result
}
//GetInfo returns info from the socket
// GetInfo returns info from the socket
func (c *Client) GetInfo() (models.ProcessInfos, error) {
result := models.ProcessInfos{}
for _, runtime := range c.runtimes {
@ -136,7 +136,7 @@ func (c *Client) GetInfo() (models.ProcessInfos, error) {
return result, nil
}
//GetVersion returns info from the socket
// GetVersion returns info from the socket
func (c *Client) GetVersion() (*HAProxyVersion, error) {
if c.haproxyVersion != nil {
return c.haproxyVersion, nil
@ -161,36 +161,36 @@ func (c *Client) GetVersion() (*HAProxyVersion, error) {
return nil, fmt.Errorf("version data not found")
}
//GetMapsPath returns runtime map file path or map id
// GetMapsPath returns runtime map file path or map id
func (c *Client) GetMapsPath(name string) (string, error) {
name = misc.SanitizeFilename(name)
//we can refer to runtime map with either id or path
if strings.HasPrefix(name, "#") { //id
// we can refer to runtime map with either id or path
if strings.HasPrefix(name, "#") { // id
return name, nil
}
//CLI
// CLI
if c.MapsDir != "" {
ext := filepath.Ext(name)
if ext != ".map" {
name = fmt.Sprintf("%s%s", name, ".map")
}
p := filepath.Join(c.MapsDir, name) //path
p := filepath.Join(c.MapsDir, name) // path
return p, nil
}
//config
// config
maps, _ := c.ShowMaps()
for _, m := range maps {
basename := filepath.Base(m.File)
if strings.TrimSuffix(basename, filepath.Ext(basename)) == name {
return m.File, nil //path from config
return m.File, nil // path from config
}
}
return "", fmt.Errorf("maps dir doesn't exists or not specified. Either use `maps-dir` CLI option or reload HAProxy if map section exists in config file")
}
//SetFrontendMaxConn set maxconn for frontend
// SetFrontendMaxConn set maxconn for frontend
func (c *Client) SetFrontendMaxConn(frontend string, maxconn int) error {
for _, runtime := range c.runtimes {
err := runtime.SetFrontendMaxConn(frontend, maxconn)
@ -201,7 +201,7 @@ func (c *Client) SetFrontendMaxConn(frontend string, maxconn int) error {
return nil
}
//SetServerAddr set ip [port] for server
// SetServerAddr set ip [port] for server
func (c *Client) SetServerAddr(backend, server string, ip string, port int) error {
for _, runtime := range c.runtimes {
err := runtime.SetServerAddr(backend, server, ip, port)
@ -212,7 +212,7 @@ func (c *Client) SetServerAddr(backend, server string, ip string, port int) erro
return nil
}
//SetServerState set state for server
// SetServerState set state for server
func (c *Client) SetServerState(backend, server string, state string) error {
for _, runtime := range c.runtimes {
err := runtime.SetServerState(backend, server, state)
@ -223,7 +223,7 @@ func (c *Client) SetServerState(backend, server string, state string) error {
return nil
}
//SetServerWeight set weight for server
// SetServerWeight set weight for server
func (c *Client) SetServerWeight(backend, server string, weight string) error {
for _, runtime := range c.runtimes {
err := runtime.SetServerWeight(backend, server, weight)
@ -234,7 +234,7 @@ func (c *Client) SetServerWeight(backend, server string, weight string) error {
return nil
}
//SetServerHealth set health for server
// SetServerHealth set health for server
func (c *Client) SetServerHealth(backend, server string, health string) error {
for _, runtime := range c.runtimes {
err := runtime.SetServerHealth(backend, server, health)
@ -245,7 +245,7 @@ func (c *Client) SetServerHealth(backend, server string, health string) error {
return nil
}
//EnableAgentCheck enable agent check for server
// EnableAgentCheck enable agent check for server
func (c *Client) EnableAgentCheck(backend, server string) error {
for _, runtime := range c.runtimes {
err := runtime.EnableAgentCheck(backend, server)
@ -256,7 +256,7 @@ func (c *Client) EnableAgentCheck(backend, server string) error {
return nil
}
//DisableAgentCheck disable agent check for server
// DisableAgentCheck disable agent check for server
func (c *Client) DisableAgentCheck(backend, server string) error {
for _, runtime := range c.runtimes {
err := runtime.DisableAgentCheck(backend, server)
@ -267,7 +267,7 @@ func (c *Client) DisableAgentCheck(backend, server string) error {
return nil
}
//EnableServer marks server as UP
// EnableServer marks server as UP
func (c *Client) EnableServer(backend, server string) error {
for _, runtime := range c.runtimes {
err := runtime.EnableServer(backend, server)
@ -278,7 +278,7 @@ func (c *Client) EnableServer(backend, server string) error {
return nil
}
//DisableServer marks server as DOWN for maintenance
// DisableServer marks server as DOWN for maintenance
func (c *Client) DisableServer(backend, server string) error {
for _, runtime := range c.runtimes {
err := runtime.DisableServer(backend, server)
@ -289,7 +289,7 @@ func (c *Client) DisableServer(backend, server string) error {
return nil
}
//SetServerAgentAddr set agent-addr for server
// SetServerAgentAddr set agent-addr for server
func (c *Client) SetServerAgentAddr(backend, server string, addr string) error {
for _, runtime := range c.runtimes {
err := runtime.SetServerAgentAddr(backend, server, addr)
@ -300,7 +300,7 @@ func (c *Client) SetServerAgentAddr(backend, server string, addr string) error {
return nil
}
//SetServerAgentSend set agent-send for server
// SetServerAgentSend set agent-send for server
func (c *Client) SetServerAgentSend(backend, server string, send string) error {
for _, runtime := range c.runtimes {
err := runtime.SetServerAgentSend(backend, server, send)
@ -311,7 +311,7 @@ func (c *Client) SetServerAgentSend(backend, server string, send string) error {
return nil
}
//GetServerState returns server runtime state
// GetServerState returns server runtime state
func (c *Client) GetServersState(backend string) (models.RuntimeServers, error) {
var prevRs models.RuntimeServers
var rs models.RuntimeServers
@ -328,7 +328,7 @@ func (c *Client) GetServersState(backend string) (models.RuntimeServers, error)
return rs, nil
}
//GetServerState returns server runtime state
// GetServerState returns server runtime state
func (c *Client) GetServerState(backend, server string) (*models.RuntimeServer, error) {
var prevRs *models.RuntimeServer
var rs *models.RuntimeServer
@ -345,7 +345,7 @@ func (c *Client) GetServerState(backend, server string) (*models.RuntimeServer,
return rs, nil
}
//SetServerCheckPort set health heck port for server
// SetServerCheckPort set health heck port for server
func (c *Client) SetServerCheckPort(backend, server string, port int) error {
for _, runtime := range c.runtimes {
err := runtime.SetServerCheckPort(backend, server, port)
@ -356,7 +356,7 @@ func (c *Client) SetServerCheckPort(backend, server string, port int) error {
return nil
}
//Show tables show tables from runtime API and return it structured, if process is 0, return for all processes
// Show tables show tables from runtime API and return it structured, if process is 0, return for all processes
func (c *Client) ShowTables(process int) (models.StickTables, error) {
tables := models.StickTables{}
for _, runtime := range c.runtimes {
@ -371,7 +371,7 @@ func (c *Client) ShowTables(process int) (models.StickTables, error) {
return tables, nil
}
//GetTableEntries returns all entries for specified table in the given process with filters and a key
// GetTableEntries returns all entries for specified table in the given process with filters and a key
func (c *Client) GetTableEntries(name string, process int, filter []string, key string) (models.StickTableEntries, error) {
var entries models.StickTableEntries
var err error
@ -388,7 +388,7 @@ func (c *Client) GetTableEntries(name string, process int, filter []string, key
return entries, nil
}
//Show table show tables {name} from runtime API associated with process id and return it structured
// Show table show tables {name} from runtime API associated with process id and return it structured
func (c *Client) ShowTable(name string, process int) (*models.StickTable, error) {
var table *models.StickTable
var err error
@ -404,7 +404,7 @@ func (c *Client) ShowTable(name string, process int) (*models.StickTable, error)
return table, nil
}
//ExecuteRaw does not procces response, just returns its values for all processes
// ExecuteRaw does not procces response, just returns its values for all processes
func (c *Client) ExecuteRaw(command string) ([]string, error) {
result := make([]string, len(c.runtimes))
for index, runtime := range c.runtimes {
@ -417,7 +417,7 @@ func (c *Client) ExecuteRaw(command string) ([]string, error) {
return result, nil
}
//ShowMaps returns structured unique map files
// ShowMaps returns structured unique map files
func (c *Client) ShowMaps() (models.Maps, error) {
maps := models.Maps{}
var lastErr error
@ -430,7 +430,7 @@ func (c *Client) ShowMaps() (models.Maps, error) {
if len(maps) == 0 {
maps = append(maps, m...)
} else {
//merge unique files from all processes
// merge unique files from all processes
for i := 0; i < len(m); i++ {
exists := false
for j := 0; j < len(maps); j++ {
@ -454,7 +454,7 @@ func (c *Client) ShowMaps() (models.Maps, error) {
return nil, nil
}
//CreateMap creates a new map file with its entries
// CreateMap creates a new map file with its entries
func (c *Client) CreateMap(file multipart.File, header multipart.FileHeader) (*models.Map, error) {
name, err := c.GetMapsPath(header.Filename)
if err != nil {
@ -467,7 +467,7 @@ func (c *Client) CreateMap(file multipart.File, header multipart.FileHeader) (*m
return m, nil
}
//GetMap returns one structured runtime map file
// GetMap returns one structured runtime map file
func (c *Client) GetMap(name string) (*models.Map, error) {
name, err := c.GetMapsPath(name)
if err != nil {
@ -486,7 +486,7 @@ func (c *Client) GetMap(name string) (*models.Map, error) {
return nil, lastErr
}
//ClearMap removes all map entries from the map file. If forceDelete is true, deletes file from disk
// ClearMap removes all map entries from the map file. If forceDelete is true, deletes file from disk
func (c *Client) ClearMap(name string, forceDelete bool) error {
name, err := c.GetMapsPath(name)
if err != nil {
@ -514,7 +514,7 @@ func (c *Client) ClearMap(name string, forceDelete bool) error {
return nil
}
//ShowMapEntries list all map entries by map file name
// ShowMapEntries list all map entries by map file name
func (c *Client) ShowMapEntries(name string) (models.MapEntries, error) {
name, err := c.GetMapsPath(name)
if err != nil {
@ -531,7 +531,7 @@ func (c *Client) ShowMapEntries(name string) (models.MapEntries, error) {
if len(entries) == 0 {
entries = append(entries, m...)
} else {
//merge unique map entries from all processes
// merge unique map entries from all processes
for i := 0; i < len(m); i++ {
exists := false
for j := 0; j < len(entries); j++ {
@ -552,7 +552,7 @@ func (c *Client) ShowMapEntries(name string) (models.MapEntries, error) {
return nil, lastErr
}
//AddMapPayload adds multiple entries to the map file
// AddMapPayload adds multiple entries to the map file
func (c *Client) AddMapPayload(name, payload string) error {
name, err := c.GetMapsPath(name)
if err != nil {
@ -571,7 +571,7 @@ func (c *Client) AddMapPayload(name, payload string) error {
return nil
}
//AddMapEntry adds an entry into the map file
// AddMapEntry adds an entry into the map file
func (c *Client) AddMapEntry(name, key, value string) error {
name, err := c.GetMapsPath(name)
if err != nil {
@ -590,7 +590,7 @@ func (c *Client) AddMapEntry(name, key, value string) error {
return nil
}
//GetMapEntry returns one map runtime setting
// GetMapEntry returns one map runtime setting
func (c *Client) GetMapEntry(name, id string) (*models.MapEntry, error) {
name, err := c.GetMapsPath(name)
if err != nil {
@ -609,7 +609,7 @@ func (c *Client) GetMapEntry(name, id string) (*models.MapEntry, error) {
return nil, lastErr
}
//SetMapEntry replace the value corresponding to each id in a map
// SetMapEntry replace the value corresponding to each id in a map
func (c *Client) SetMapEntry(name, id, value string) error {
name, err := c.GetMapsPath(name)
if err != nil {
@ -628,7 +628,7 @@ func (c *Client) SetMapEntry(name, id, value string) error {
return nil
}
//DeleteMapEntry deletes all the map entries from the map by its id
// DeleteMapEntry deletes all the map entries from the map by its id
func (c *Client) DeleteMapEntry(name, id string) error {
name, err := c.GetMapsPath(name)
if err != nil {

@ -27,7 +27,7 @@ var oncePossibleStates sync.Once
var possibleHealths map[string]struct{}
var oncePossibleHealths sync.Once
//ServerStateValid checks if server state is valid
// ServerStateValid checks if server state is valid
func ServerStateValid(state string) bool {
oncePossibleStates.Do(func() {
possibleStates = map[string]struct{}{
@ -40,7 +40,7 @@ func ServerStateValid(state string) bool {
return ok
}
//ServerHealthValid checks if server health is valid
// ServerHealthValid checks if server health is valid
func ServerHealthValid(health string) bool {
oncePossibleHealths.Do(func() {
possibleHealths = map[string]struct{}{
@ -53,7 +53,7 @@ func ServerHealthValid(health string) bool {
return ok
}
//ServerWeightValid checks if server state is valid
// ServerWeightValid checks if server state is valid
func ServerWeightValid(weight string) bool {
var n int64
var err error

@ -22,19 +22,19 @@ import (
"time"
)
//TaskResponse ...
// TaskResponse ...
type TaskResponse struct {
result string
err error
}
//Task has command to execute on runtime api, and response channel for result
// Task has command to execute on runtime api, and response channel for result
type Task struct {
command string
response chan TaskResponse
}
//SingleRuntime handles one runtime API
// SingleRuntime handles one runtime API
type SingleRuntime struct {
jobs chan Task
socketPath string
@ -42,10 +42,10 @@ type SingleRuntime struct {
process int
}
//Init must be given path to runtime socket and worker number. If in master-worker mode,
//give the path to the master socket path, and non 0 number for workers. Process is for
//nbproc > 1. In master-worker mode it's the same as the worker number, but when having
//multiple stats socket lines bound to processes then use the correct process number
// Init must be given path to runtime socket and worker number. If in master-worker mode,
// give the path to the master socket path, and non 0 number for workers. Process is for
// nbproc > 1. In master-worker mode it's the same as the worker number, but when having
// multiple stats socket lines bound to processes then use the correct process number
func (s *SingleRuntime) Init(socketPath string, worker int, process int) error {
s.socketPath = socketPath
s.jobs = make(chan Task)
@ -56,22 +56,21 @@ func (s *SingleRuntime) Init(socketPath string, worker int, process int) error {
}
func (s *SingleRuntime) handleIncommingJobs() {
for {
select {
case job := <-s.jobs:
result, err := s.readFromSocket(job.command)
if err != nil {
job.response <- TaskResponse{err: err}
} else {
job.response <- TaskResponse{result: result}
}
for job := range s.jobs {
result, err := s.readFromSocket(job.command)
if err != nil {
job.response <- TaskResponse{err: err}
} else {
job.response <- TaskResponse{result: result}
}
}
}
func (s *SingleRuntime) readFromSocket(command string) (string, error) {
api, err := net.Dial("unix", s.socketPath)
if err != nil {
var api net.Conn
var err error
if api, err = net.Dial("unix", s.socketPath); err != nil {
return "", err
}
fullCommand := fmt.Sprintf("set severity-output number;%s\n", command)
@ -91,52 +90,26 @@ func (s *SingleRuntime) readFromSocket(command string) (string, error) {
buf := make([]byte, bufferSize)
var data strings.Builder
for {
n, err := api.Read(buf)
if err != nil {
if n, readErr := api.Read(buf); readErr != nil {
break
} else {
data.Write(buf[0:n])
}
data.Write(buf[0:n])
}
api.Close()
if err != nil {
return "", err
}
_ = api.Close()
result := strings.TrimSuffix(data.String(), "\n> ")
result = strings.TrimSuffix(result, "\n")
return result, nil
}
func (s *SingleRuntime) readFromSocketClean(command string) (string, error) {
api, err := net.Dial("unix", s.socketPath)
if err != nil {
return "", err
}
defer api.Close()
_, err = api.Write([]byte(fmt.Sprintf("%s\n", command)))
if err != nil {
return "", nil
}
time.Sleep(1e9)
buf := make([]byte, 1024)
var data strings.Builder
for {
n, err := api.Read(buf)
if err != nil {
break
}
data.Write(buf[0:n])
}
return data.String(), nil
}
//ExecuteRaw executes command on runtime API and returns raw result
// ExecuteRaw executes command on runtime API and returns raw result
func (s *SingleRuntime) ExecuteRaw(command string) (string, error) {
//allow one retry if connection breaks temporarily
// allow one retry if connection breaks temporarily
return s.executeRaw(command, 1)
}
//Execute executes command on runtime API
// Execute executes command on runtime API
func (s *SingleRuntime) Execute(command string) error {
rawdata, err := s.ExecuteRaw(command)
if err != nil {

@ -24,7 +24,7 @@ import (
"github.com/haproxytech/models/v2"
)
//SetServerAddr set ip [port] for server
// SetServerAddr set ip [port] for server
func (s *SingleRuntime) SetServerAddr(backend, server string, ip string, port int) error {
var cmd string
if port > 0 {
@ -35,7 +35,7 @@ func (s *SingleRuntime) SetServerAddr(backend, server string, ip string, port in
return s.Execute(cmd)
}
//SetServerState set state for server
// SetServerState set state for server
func (s *SingleRuntime) SetServerState(backend, server string, state string) error {
if !ServerStateValid(state) {
return fmt.Errorf("bad request")
@ -44,7 +44,7 @@ func (s *SingleRuntime) SetServerState(backend, server string, state string) err
return s.Execute(cmd)
}
//SetServerWeight set weight for server
// SetServerWeight set weight for server
func (s *SingleRuntime) SetServerWeight(backend, server string, weight string) error {
if !ServerWeightValid(weight) {
return fmt.Errorf("bad request")
@ -53,7 +53,7 @@ func (s *SingleRuntime) SetServerWeight(backend, server string, weight string) e
return s.Execute(cmd)
}
//SetServerHealth set health for server
// SetServerHealth set health for server
func (s *SingleRuntime) SetServerHealth(backend, server string, health string) error {
if !ServerHealthValid(health) {
return fmt.Errorf("bad request")
@ -62,7 +62,7 @@ func (s *SingleRuntime) SetServerHealth(backend, server string, health string) e
return s.Execute(cmd)
}
//SetServerCheckPort set health heck port for server
// SetServerCheckPort set health heck port for server
func (s *SingleRuntime) SetServerCheckPort(backend, server string, port int) error {
if !(port > 0 && port <= 65535) {
return fmt.Errorf("bad request")
@ -70,43 +70,43 @@ func (s *SingleRuntime) SetServerCheckPort(backend, server string, port int) err
return s.Execute(fmt.Sprintf("set server %s/%s check-port %d", backend, server, port))
}
//EnableAgentCheck enable agent check for server
// EnableAgentCheck enable agent check for server
func (s *SingleRuntime) EnableAgentCheck(backend, server string) error {
cmd := fmt.Sprintf("enable agent %s/%s", backend, server)
return s.Execute(cmd)
}
//DisableAgentCheck disable agent check for server
// DisableAgentCheck disable agent check for server
func (s *SingleRuntime) DisableAgentCheck(backend, server string) error {
cmd := fmt.Sprintf("disable agent %s/%s", backend, server)
return s.Execute(cmd)
}
//EnableServer marks server as UP
// EnableServer marks server as UP
func (s *SingleRuntime) EnableServer(backend, server string) error {
cmd := fmt.Sprintf("enable server %s/%s", backend, server)
return s.Execute(cmd)
}
//DisableServer marks server as DOWN for maintenanc
// DisableServer marks server as DOWN for maintenanc
func (s *SingleRuntime) DisableServer(backend, server string) error {
cmd := fmt.Sprintf("disable server %s/%s", backend, server)
return s.Execute(cmd)
}
//SetServerAgentAddr set agent-addr for server
// SetServerAgentAddr set agent-addr for server
func (s *SingleRuntime) SetServerAgentAddr(backend, server string, addr string) error {
cmd := fmt.Sprintf("set server %s/%s agent-addr %s", backend, server, addr)
return s.Execute(cmd)
}
//SetServerAgentSend set agent-send for server
// SetServerAgentSend set agent-send for server
func (s *SingleRuntime) SetServerAgentSend(backend, server string, send string) error {
cmd := fmt.Sprintf("set server %s/%s agent-send %s", backend, server, send)
return s.Execute(cmd)
}
//GetServersState returns servers runtime state
// GetServersState returns servers runtime state
func (s *SingleRuntime) GetServersState(backend string) (models.RuntimeServers, error) {
cmd := fmt.Sprintf("show servers state %s", backend)
result, err := s.ExecuteWithResponse(cmd)
@ -116,7 +116,7 @@ func (s *SingleRuntime) GetServersState(backend string) (models.RuntimeServers,
return parseRuntimeServers(result)
}
//GetServersState returns server runtime state
// GetServersState returns server runtime state
func (s *SingleRuntime) GetServerState(backend, server string) (*models.RuntimeServer, error) {
cmd := fmt.Sprintf("show servers state %s", backend)
result, err := s.ExecuteWithResponse(cmd)
@ -126,7 +126,7 @@ func (s *SingleRuntime) GetServerState(backend, server string) (*models.RuntimeS
lines := strings.Split(result, "\n")
if strings.TrimSpace(lines[0]) != "1" {
return nil, fmt.Errorf("Unsupported output format version, supporting format version 1")
return nil, fmt.Errorf("unsupported output format version, supporting format version 1")
}
for _, line := range lines {
@ -147,7 +147,7 @@ func parseRuntimeServers(output string) (models.RuntimeServers, error) {
result := models.RuntimeServers{}
if strings.TrimSpace(lines[0]) != "1" {
return nil, fmt.Errorf("Unsupported output format version, supporting format version 1")
return nil, fmt.Errorf("unsupported output format version, supporting format version 1")
}
for _, line := range lines[1:] {
if strings.TrimSpace(line) == "" || strings.HasPrefix(line, "#") || strings.TrimSpace(line) == "1" {

@ -23,7 +23,7 @@ import (
"github.com/mitchellh/mapstructure"
)
//GetStats fetches HAProxy stats from runtime API
// GetStats fetches HAProxy stats from runtime API
func (s *SingleRuntime) GetStats() *models.NativeStatsCollection {
rAPI := ""
if s.worker != 0 {
@ -40,7 +40,6 @@ func (s *SingleRuntime) GetStats() *models.NativeStatsCollection {
lines := strings.Split(rawdata[2:], "\n")
stats := []*models.NativeStat{}
keys := strings.Split(lines[0], ",")
//data := []map[string]string{}
for i := 1; i < len(lines); i++ {
data := map[string]string{}
line := strings.Split(lines[i], ",")

@ -8,7 +8,7 @@ import (
"github.com/haproxytech/models/v2"
)
//ShowTables returns Stick Tables descriptions from runtime
// ShowTables returns Stick Tables descriptions from runtime
func (s *SingleRuntime) ShowTables() (models.StickTables, error) {
response, err := s.ExecuteWithResponse("show table")
if err != nil {
@ -17,7 +17,7 @@ func (s *SingleRuntime) ShowTables() (models.StickTables, error) {
return s.parseStickTables(response), nil
}
//ShowTables returns one Stick Table descriptions from runtime
// ShowTables returns one Stick Table descriptions from runtime
func (s *SingleRuntime) ShowTable(name string) (*models.StickTable, error) {
response, err := s.ExecuteWithResponse("show table")
if err != nil {
@ -36,7 +36,7 @@ func (s *SingleRuntime) ShowTable(name string) (*models.StickTable, error) {
return nil, nil
}
//GetTableEntries returns Stick Tables entries
// GetTableEntries returns Stick Tables entries
func (s *SingleRuntime) GetTableEntries(name string, filter []string, key string) (models.StickTableEntries, error) {
cmd := fmt.Sprintf("show table %s", name)

@ -11,73 +11,73 @@ import (
// IRuntimeClient ...
type IRuntimeClient interface {
//Init must be given path to runtime socket and nbproc that is not 0 when in master worker mode
// Init must be given path to runtime socket and nbproc that is not 0 when in master worker mode
//
//Deprecated: use InitWithSockets or InitWithMasterSocket instead
// Deprecated: use InitWithSockets or InitWithMasterSocket instead
Init(socketPath []string, masterSocketPath string, nbproc int) error
//GetMapsPath returns runtime map file path or map id
// GetMapsPath returns runtime map file path or map id
GetMapsPath(name string) (string, error)
InitWithSockets(socketPath map[int]string) error
InitWithMasterSocket(masterSocketPath string, nbproc int) error
//GetStats returns stats from the socket
// GetStats returns stats from the socket
GetStats() models.NativeStats
//GetInfo returns info from the socket
// GetInfo returns info from the socket
GetInfo() (models.ProcessInfos, error)
//SetFrontendMaxConn set maxconn for frontend
// SetFrontendMaxConn set maxconn for frontend
SetFrontendMaxConn(frontend string, maxconn int) error
//SetServerAddr set ip [port] for server
// SetServerAddr set ip [port] for server
SetServerAddr(backend, server string, ip string, port int) error
//SetServerState set state for server
// SetServerState set state for server
SetServerState(backend, server string, state string) error
//SetServerWeight set weight for server
// SetServerWeight set weight for server
SetServerWeight(backend, server string, weight string) error
//SetServerHealth set health for server
// SetServerHealth set health for server
SetServerHealth(backend, server string, health string) error
//EnableAgentCheck enable agent check for server
// EnableAgentCheck enable agent check for server
EnableAgentCheck(backend, server string) error
//DisableAgentCheck disable agent check for server
// DisableAgentCheck disable agent check for server
DisableAgentCheck(backend, server string) error
//EnableServer marks server as UP
// EnableServer marks server as UP
EnableServer(backend, server string) error
//DisableServer marks server as DOWN for maintenance
// DisableServer marks server as DOWN for maintenance
DisableServer(backend, server string) error
//SetServerAgentAddr set agent-addr for server
// SetServerAgentAddr set agent-addr for server
SetServerAgentAddr(backend, server string, addr string) error
//SetServerAgentSend set agent-send for server
// SetServerAgentSend set agent-send for server
SetServerAgentSend(backend, server string, send string) error
//GetServerState returns server runtime state
// GetServerState returns server runtime state
GetServersState(backend string) (models.RuntimeServers, error)
//GetServerState returns server runtime state
// GetServerState returns server runtime state
GetServerState(backend, server string) (*models.RuntimeServer, error)
//SetServerCheckPort set health heck port for server
// SetServerCheckPort set health heck port for server
SetServerCheckPort(backend, server string, port int) error
//Show tables show tables from runtime API and return it structured, if process is 0, return for all processes
// Show tables show tables from runtime API and return it structured, if process is 0, return for all processes
ShowTables(process int) (models.StickTables, error)
//GetTableEntries returns all entries for specified table in the given process with filters and a key
// GetTableEntries returns all entries for specified table in the given process with filters and a key
GetTableEntries(name string, process int, filter []string, key string) (models.StickTableEntries, error)
//Show table show tables {name} from runtime API associated with process id and return it structured
// Show table show tables {name} from runtime API associated with process id and return it structured
ShowTable(name string, process int) (*models.StickTable, error)
//ExecuteRaw does not procces response, just returns its values for all processes
// ExecuteRaw does not procces response, just returns its values for all processes
ExecuteRaw(command string) ([]string, error)
//ShowMaps returns structured unique map files
// ShowMaps returns structured unique map files
ShowMaps() (models.Maps, error)
//CreateMap creates a new map file with its entries
// CreateMap creates a new map file with its entries
CreateMap(file multipart.File, header multipart.FileHeader) (*models.Map, error)
//GetMap returns one structured runtime map file
// GetMap returns one structured runtime map file
GetMap(name string) (*models.Map, error)
//ClearMap removes all map entries from the map file. If forceDelete is true, deletes file from disk
// ClearMap removes all map entries from the map file. If forceDelete is true, deletes file from disk
ClearMap(name string, forceDelete bool) error
//ShowMapEntries list all map entries by map file name
// ShowMapEntries list all map entries by map file name
ShowMapEntries(name string) (models.MapEntries, error)
// AddMapPayload adds multiple entries to the map file
AddMapPayload(name, payload string) error
//AddMapEntry adds an entry into the map file
// AddMapEntry adds an entry into the map file
AddMapEntry(name, key, value string) error
//GetMapEntry returns one map runtime setting
// GetMapEntry returns one map runtime setting
GetMapEntry(name, id string) (*models.MapEntry, error)
//SetMapEntry replace the value corresponding to each id in a map
// SetMapEntry replace the value corresponding to each id in a map
SetMapEntry(name, id, value string) error
//DeleteMapEntry deletes all the map entries from the map by its id
// DeleteMapEntry deletes all the map entries from the map by its id
DeleteMapEntry(name, id string) error
ParseMapEntries(output string) models.MapEntries
// ParseMapEntriesFromFile reads entries from file

Loading…
Cancel
Save