Skip to content

Commit 2dcffdd

Browse files
authored
add license support (#414)
1 parent 09a47e4 commit 2dcffdd

File tree

2 files changed

+135
-5
lines changed

2 files changed

+135
-5
lines changed

client/nginx.go

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import (
99
"io"
1010
"net/http"
1111
"reflect"
12+
"regexp"
1213
"slices"
14+
"strconv"
1315
"strings"
1416
"sync"
1517
"time"
@@ -41,11 +43,12 @@ var (
4143
)
4244

4345
var (
44-
ErrParameterRequired = errors.New("parameter is required")
45-
ErrServerNotFound = errors.New("server not found")
46-
ErrServerExists = errors.New("server already exists")
47-
ErrNotSupported = errors.New("not supported")
48-
ErrInvalidTimeout = errors.New("invalid timeout")
46+
ErrParameterRequired = errors.New("parameter is required")
47+
ErrServerNotFound = errors.New("server not found")
48+
ErrServerExists = errors.New("server already exists")
49+
ErrNotSupported = errors.New("not supported")
50+
ErrInvalidTimeout = errors.New("invalid timeout")
51+
ErrPlusVersionNotFound = errors.New("plus version not found in the input string")
4952
)
5053

5154
// NginxClient lets you access NGINX Plus API.
@@ -193,6 +196,20 @@ type NginxInfo struct {
193196
ParentProcessID uint64 `json:"ppid"`
194197
}
195198

199+
// LicenseReporting contains information about license status for NGINX Plus.
200+
type LicenseReporting struct {
201+
Healthy bool
202+
Fails uint64
203+
Grace uint64
204+
}
205+
206+
// NginxLicense contains licensing information about NGINX Plus.
207+
type NginxLicense struct {
208+
ActiveTill uint64 `json:"active_till"`
209+
Eval bool
210+
Reporting LicenseReporting
211+
}
212+
196213
// Caches is a map of cache stats by cache zone.
197214
type Caches = map[string]HTTPCache
198215

@@ -1553,6 +1570,30 @@ func (client *NginxClient) GetNginxInfo(ctx context.Context) (*NginxInfo, error)
15531570
return &info, nil
15541571
}
15551572

1573+
// GetNginxLicense returns Nginx License data with a context.
1574+
func (client *NginxClient) GetNginxLicense(ctx context.Context) (*NginxLicense, error) {
1575+
var data NginxLicense
1576+
1577+
info, err := client.GetNginxInfo(ctx)
1578+
if err != nil {
1579+
return nil, fmt.Errorf("failed to get nginx info: %w", err)
1580+
}
1581+
release, err := extractPlusVersionValues(info.Build)
1582+
if err != nil {
1583+
return nil, fmt.Errorf("failed to get nginx plus release: %w", err)
1584+
}
1585+
1586+
if (client.apiVersion < 9) || (release < 33) {
1587+
return &data, nil
1588+
}
1589+
1590+
err = client.get(ctx, "license", &data)
1591+
if err != nil {
1592+
return nil, fmt.Errorf("failed to get license: %w", err)
1593+
}
1594+
return &data, nil
1595+
}
1596+
15561597
// GetCaches returns Cache stats with a context.
15571598
func (client *NginxClient) GetCaches(ctx context.Context) (*Caches, error) {
15581599
var caches Caches
@@ -1988,3 +2029,22 @@ func (client *NginxClient) GetWorkers(ctx context.Context) ([]*Workers, error) {
19882029
}
19892030
return workers, nil
19902031
}
2032+
2033+
var rePlus = regexp.MustCompile(`-r(\d+)`)
2034+
2035+
// extractPlusVersionValues.
2036+
func extractPlusVersionValues(input string) (int, error) {
2037+
var rValue int
2038+
matches := rePlus.FindStringSubmatch(input)
2039+
2040+
if len(matches) < 1 {
2041+
return 0, fmt.Errorf("%w [%s]", ErrPlusVersionNotFound, input)
2042+
}
2043+
2044+
rValue, err := strconv.Atoi(matches[1])
2045+
if err != nil {
2046+
return 0, fmt.Errorf("failed to convert NGINX Plus release to integer: %w", err)
2047+
}
2048+
2049+
return rValue, nil
2050+
}

client/nginx_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -910,3 +910,73 @@ func TestGetMaxAPIVersionClient(t *testing.T) {
910910
t.Fatalf("expected %v, got %v", c.apiVersion, maxVer)
911911
}
912912
}
913+
914+
func TestExtractPlusVersion(t *testing.T) {
915+
t.Parallel()
916+
tests := []struct {
917+
name string
918+
version string
919+
expected int
920+
}{
921+
{
922+
name: "r32",
923+
version: "nginx-plus-r32",
924+
expected: 32,
925+
},
926+
{
927+
name: "r32p1",
928+
version: "nginx-plus-r32-p1",
929+
expected: 32,
930+
},
931+
{
932+
name: "r32p2",
933+
version: "nginx-plus-r32-p2",
934+
expected: 32,
935+
},
936+
{
937+
name: "r33",
938+
version: "nginx-plus-r33",
939+
expected: 33,
940+
},
941+
}
942+
943+
for _, test := range tests {
944+
t.Run(test.name, func(t *testing.T) {
945+
t.Parallel()
946+
version, err := extractPlusVersionValues(test.version)
947+
if err != nil {
948+
t.Error(err)
949+
}
950+
if version != test.expected {
951+
t.Errorf("values do not match, got: %d, expected %d)", version, test.expected)
952+
}
953+
})
954+
}
955+
}
956+
957+
func TestExtractPlusVersionNegativeCase(t *testing.T) {
958+
t.Parallel()
959+
tests := []struct {
960+
name string
961+
version string
962+
}{
963+
{
964+
name: "no-number",
965+
version: "nginx-plus-rxx",
966+
},
967+
{
968+
name: "extra-chars",
969+
version: "nginx-plus-rxx4343",
970+
},
971+
}
972+
973+
for _, test := range tests {
974+
t.Run(test.name, func(t *testing.T) {
975+
t.Parallel()
976+
_, err := extractPlusVersionValues(test.version)
977+
if err == nil {
978+
t.Errorf("Expected error but got %v", err)
979+
}
980+
})
981+
}
982+
}

0 commit comments

Comments
 (0)