Skip to content

Commit

Permalink
lang: funcs: New simple funcs
Browse files Browse the repository at this point in the history
  • Loading branch information
S-ign committed Mar 5, 2021
1 parent 1873e02 commit c87d2b4
Show file tree
Hide file tree
Showing 5 changed files with 250 additions and 0 deletions.
12 changes: 12 additions & 0 deletions examples/lang/ipport.mcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import "net"

$ipport = net.ip_port("192.168.1.1", "433")

print "ipport" {
msg => $ipport,
}

file "/tmp/mgmt/ipport" {
state => $const.res.file.state.exists,
content => $ipport,
}
58 changes: 58 additions & 0 deletions lang/funcs/core/net/ip_port.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Mgmt
// Copyright (C) 2013-2021+ James Shubin and the project contributors
// Written by James Shubin <james@shubin.ca> and the project contributors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package corenet

import (
"errors"
"fmt"
"net"
"strconv"

"github.com/purpleidea/mgmt/lang/funcs/simple"
"github.com/purpleidea/mgmt/lang/types"
)

func init() {
simple.ModuleRegister(ModuleName, "ip_port", &types.FuncValue{
T: types.NewType("func(ip str, port str) str"),
V: IPPort,
})
}

// IPPort returns the combind IPv4/IPv6:(input[0]) and Port:(input[1]). Returns
// error if IPv4/IPv6 string is incorrect format or Port not in range 0-65536.
func IPPort(input []types.Value) (types.Value, error) {
ip := net.ParseIP(input[0].Str()) // Is nil if incorrect format.
ipStr := input[0].Str()
port := input[1].Str()
portInt, err := strconv.Atoi(port)

if ip == nil {
return &types.StrValue{V: ""}, errors.New("incorrect ip format")
}
if err != nil {
return &types.StrValue{V: ""}, fmt.Errorf("err converting str to int %v", err)
}
if portInt < 0 || portInt > 65536 {
return &types.StrValue{V: ""}, errors.New("port not in range 0-65536")
}

return &types.StrValue{
V: ipStr + ":" + port,
}, nil
}
76 changes: 76 additions & 0 deletions lang/funcs/core/net/ip_port_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Mgmt
// Copyright (C) 2013-2021+ James Shubin and the project contributors
// Written by James Shubin <james@shubin.ca> and the project contributors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package corenet

import (
"errors"
"testing"

"github.com/purpleidea/mgmt/lang/types"
)

func TestIPPort(t *testing.T) {
ipporttests := []struct {
name string
ip string
port string
expected string
err error
}{
// Success
{"correct ipv4 and port", "192.168.1.1", "80", "192.168.1.1:80", nil},
{"correct ipv6 and port", "2345:0425:2CA1:0000:0000:0567:5673:23b5", "8080", "2345:0425:2CA1:0000:0000:0567:5673:23b5:8080", nil},
{"correct ipv4 and port - allow port 0", "192.168.1.1", "0", "192.168.1.1:0", nil},
{"correct ipv6 and port - allows port 65536", "2345:0425:2CA1::0567:5673:23b5", "65536", "2345:0425:2CA1::0567:5673:23b5:65536", nil},
// Fail
{"incorrect ipv4 - octet over 255", "392.868.11.79", "80", "", errors.New("incorrect ip format")},
{"incorrect ipv4 - CIDR format", "10.10.10.100/8", "23", "", errors.New("incorrect ip format")},
{"incorrect ipv4 - dots...", "172.16.10..254", "23", "", errors.New("incorrect ip format")},
{"incorrect ipv6 - double double colon", "5678:A425:2CA1::0567::5673:23b5", "80", "", errors.New("incorrect ip format")},
{"incorrect ipv6 - non hex chars", "M678:Z425:2CA1::05X7:T673:23b5", "1234", "", errors.New("incorrect ip format")},
{"incorrect port - outside of range", "192.168.1.1", "65537", "", errors.New("port not in range 0-65536")},
{"incorrect port - negative port number", "192.168.1.1", "-9483670", "", errors.New("port not in range 0-65536")},
}

for _, test := range ipporttests {
t.Run(test.name, func(t *testing.T) {
output, err := IPPort([]types.Value{
&types.StrValue{V: test.ip},
&types.StrValue{V: test.port},
})
expectedStr := &types.StrValue{V: test.expected}

if test.err != nil && err.Error() != test.err.Error() {
t.Errorf("ip: %s, port %s, expected error: %q, got %q", test.ip, test.port, test.err, err)
return
} else if test.err != nil && err == nil {
t.Errorf("ip: %s, port: %s, expected error: %v, but got nil", test.ip, test.port, test.err)
return
} else if test.err == nil && err != nil {
t.Errorf("ip: %s, port %s, did not expect error but got: %#v", test.ip, test.port, err)
return
}
if err1 := output.Cmp(expectedStr); err1 != nil {
t.Errorf("ip: %s, port: %s, expected: %s, got: %s", test.ip, test.port, expectedStr, output)
return
}

})
}

}
39 changes: 39 additions & 0 deletions lang/funcs/core/strings/contains_func.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Mgmt
// Copyright (C) 2013-2021+ James Shubin and the project contributors
// Written by James Shubin <james@shubin.ca> and the project contributors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package corestrings

import (
"strings"

"github.com/purpleidea/mgmt/lang/funcs/simple"
"github.com/purpleidea/mgmt/lang/types"
)

func init() {
simple.ModuleRegister(ModuleName, "contains", &types.FuncValue{
T: types.NewType("func(s str, substr str) bool"),
V: Contains,
})
}

// Contains splits the input string using the separator and returns the segments as
// a list.
func Contains(input []types.Value) (types.Value, error) {
s, substr := input[0].Str(), input[1].Str()
return &types.BoolValue{V: strings.Contains(s, substr)}, nil
}
65 changes: 65 additions & 0 deletions lang/funcs/core/strings/contains_func_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Mgmt
// Copyright (C) 2013-2021+ James Shubin and the project contributors
// Written by James Shubin <james@shubin.ca> and the project contributors
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

package corestrings

import (
"testing"

"github.com/purpleidea/mgmt/lang/types"
)

func TestContains(t *testing.T) {
containsTests := []struct {
name string
s string
substr string
expected bool
err error
}{
// Success
{"does contain", "tomorrow", "row", true, nil},
{"does not contain", "fighter", "light", false, nil},
}

for _, test := range containsTests {
t.Run(test.name, func(t *testing.T) {
output, err := Contains([]types.Value{
&types.StrValue{V: test.s},
&types.StrValue{V: test.substr},
})
expectedStr := &types.BoolValue{V: test.expected}

if test.err != nil && err.Error() != test.err.Error() {
t.Errorf("s: %s, substr %s, expected error: %q, got %q", test.s, test.substr, test.err, err)
return
} else if test.err != nil && err == nil {
t.Errorf("s: %s, substr: %s, expected error: %v, but got nil", test.s, test.substr, test.err)
return
} else if test.err == nil && err != nil {
t.Errorf("s: %s, substr %s, did not expect error but got: %#v", test.s, test.substr, err)
return
}
if err1 := output.Cmp(expectedStr); err1 != nil {
t.Errorf("s: %s, substr: %s, expected: %s, got: %s", test.s, test.substr, expectedStr, output)
return
}

})
}

}

0 comments on commit c87d2b4

Please sign in to comment.