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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## [master](https://github.com/arangodb/kube-arangodb/tree/master) (N/A)
- (Bugfix) (Platform) Increase memory limit for Inventory
- (Feature) (LM) Inventory Generator
- (Feature) (License) Activation CLI

## [1.3.1](https://github.com/arangodb/kube-arangodb/tree/1.3.1) (2025-10-07)
- (Documentation) Add ArangoPlatformStorage Docs & Examples
Expand Down
84 changes: 82 additions & 2 deletions docs/cli/arangodb_operator_platform.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Usage:
Available Commands:
completion Generate the autocompletion script for the specified shell
help Help about any command
license License Package related operations
license License related Operations
package Release Package related operations

Flags:
Expand All @@ -41,6 +41,7 @@ Available Commands:
import Imports the package from the ZIP format
install Installs the specified setup of the platform
merge Merges definitions into single file
registry Points all images to the new registry

Flags:
-h, --help help for package
Expand Down Expand Up @@ -96,13 +97,16 @@ Global Flags:

[START_INJECT]: # (arangodb_operator_platform_license_cmd)
```
License Package related operations
License related Operations

Usage:
arangodb_operator_platform license [command]

Available Commands:
activate Activates the License on ArangoDB Endpoint
generate Generate the License
inventory Inventory Generator
secret Creates Platform Secret with Registry credentials

Flags:
-h, --help help for license
Expand Down Expand Up @@ -138,3 +142,79 @@ Global Flags:
-n, --namespace string Kubernetes Namespace (default "default")
```
[END_INJECT]: # (arangodb_operator_platform_license_inventory_cmd)

# ArangoDB Operator Platform License Activate Command

[START_INJECT]: # (arangodb_operator_platform_license_activate_cmd)
```
Activates the License on ArangoDB Endpoint

Usage:
arangodb_operator_platform license activate [flags]

Flags:
--arango.authentication string Arango Endpoint Auth Method. One of: Disabled, Basic, Token (default "Disabled")
--arango.basic.password string Arango Password for Basic Authentication
--arango.basic.username string Arango Username for Basic Authentication
--arango.endpoint strings Arango Endpoint
--arango.insecure Arango Endpoint Insecure
--arango.token string Arango JWT Token for Authentication
-h, --help help for activate
--license.client.id string LicenseManager Client ID
--license.client.secret string LicenseManager Client Secret
--license.client.stage strings LicenseManager Stages (default [prd])
--license.endpoint string LicenseManager Endpoint (default "license.arango.ai")
--license.interval duration Interval of the license synchronization

Global Flags:
--kubeconfig string Kubernetes Config File
-n, --namespace string Kubernetes Namespace (default "default")
```
[END_INJECT]: # (arangodb_operator_platform_license_activate_cmd)

# ArangoDB Operator Platform License Generate Command

[START_INJECT]: # (arangodb_operator_platform_license_generate_cmd)
```
Generate the License

Usage:
arangodb_operator_platform license generate [flags]

Flags:
--deployment.id string Deployment ID
-h, --help help for generate
--inventory string Path to the Inventory File
--license.client.id string LicenseManager Client ID
--license.client.secret string LicenseManager Client Secret
--license.client.stage strings LicenseManager Stages (default [prd])
--license.endpoint string LicenseManager Endpoint (default "license.arango.ai")

Global Flags:
--kubeconfig string Kubernetes Config File
-n, --namespace string Kubernetes Namespace (default "default")
```
[END_INJECT]: # (arangodb_operator_platform_license_generate_cmd)

# ArangoDB Operator Platform License Secret Command

[START_INJECT]: # (arangodb_operator_platform_license_secret_cmd)
```
Creates Platform Secret with Registry credentials

Usage:
arangodb_operator_platform license secret [flags]

Flags:
-h, --help help for secret
--license.client.id string LicenseManager Client ID
--license.client.secret string LicenseManager Client Secret
--license.client.stage strings LicenseManager Stages (default [prd])
--license.endpoint string LicenseManager Endpoint (default "license.arango.ai")
--secret string Kubernetes Secret Name

Global Flags:
--kubeconfig string Kubernetes Config File
-n, --namespace string Kubernetes Namespace (default "default")
```
[END_INJECT]: # (arangodb_operator_platform_license_secret_cmd)
41 changes: 23 additions & 18 deletions internal/docs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,8 @@ func (d DocDefinitions) RenderMarkdown(t *testing.T, repositoryPath string) []by

els += 1

write(t, out, "### %s\n\n", el.Path)
write(t, out, "Type: `%s` <sup>[\\[ref\\]](%s/%s#L%d)</sup>\n\n", el.Type, repositoryPath, el.File, el.Line)
writef(t, out, "### %s\n\n", el.Path)
writef(t, out, "Type: `%s` <sup>[\\[ref\\]](%s/%s#L%d)</sup>\n\n", el.Type, repositoryPath, el.File, el.Line)

if grade := el.Grade; grade != nil {
switch grade.Grade {
Expand All @@ -88,44 +88,44 @@ func (d DocDefinitions) RenderMarkdown(t *testing.T, repositoryPath string) []by
write(t, out, "> ***DEPRECATED***\n")
write(t, out, "> \n")
for _, line := range grade.Message {
write(t, out, "> **%s**\n", line)
writef(t, out, "> **%s**\n", line)
}
write(t, out, "\n")
case DocDefinitionGradeAlpha:
write(t, out, "> [!WARNING]\n")
write(t, out, "> ***ALPHA***\n")
write(t, out, "> \n")
for _, line := range grade.Message {
write(t, out, "> **%s**\n", line)
writef(t, out, "> **%s**\n", line)
}
write(t, out, "\n")
case DocDefinitionGradeBeta:
write(t, out, "> [!IMPORTANT]\n")
write(t, out, "> ***BETA***\n")
write(t, out, "> \n")
for _, line := range grade.Message {
write(t, out, "> **%s**\n", line)
writef(t, out, "> **%s**\n", line)
}
write(t, out, "\n")
}
}

if d := el.Important; d != nil {
write(t, out, "> [!IMPORTANT]\n")
write(t, out, "> **%s**\n\n", *d)
writef(t, out, "> **%s**\n\n", *d)
}

if d := el.Required; d != nil {
if *d == "" {
write(t, out, "This field is **required**\n\n")
} else {
write(t, out, "This field is **required**: %s\n\n", *d)
writef(t, out, "This field is **required**: %s\n\n", *d)
}
}

if len(el.Docs) > 0 {
for _, doc := range el.Docs {
write(t, out, "%s\n", doc)
writef(t, out, "%s\n", doc)
}
write(t, out, "\n")
}
Expand All @@ -136,9 +136,9 @@ func (d DocDefinitions) RenderMarkdown(t *testing.T, repositoryPath string) []by
for _, link := range el.Links {
z := goStrings.Split(link, "|")
if len(z) == 1 {
write(t, out, "* [Documentation](%s)\n", z[0])
writef(t, out, "* [Documentation](%s)\n", z[0])
} else if len(z) == 2 {
write(t, out, "* [%s](%s)\n", z[0], z[1])
writef(t, out, "* [%s](%s)\n", z[0], z[1])
} else {
require.Fail(t, "Invalid link format")
}
Expand All @@ -151,7 +151,7 @@ func (d DocDefinitions) RenderMarkdown(t *testing.T, repositoryPath string) []by
write(t, out, "Example:\n")
write(t, out, "```yaml\n")
for _, example := range el.Example {
write(t, out, "%s\n", example)
writef(t, out, "%s\n", example)
}
write(t, out, "```\n\n")
}
Expand All @@ -167,25 +167,25 @@ func (d DocDefinitions) RenderMarkdown(t *testing.T, repositoryPath string) []by
}

if len(z) == 1 {
write(t, out, "* %s\n", snip)
writef(t, out, "* %s\n", snip)
} else if len(z) == 2 {
write(t, out, "* %s - %s\n", snip, z[1])
writef(t, out, "* %s - %s\n", snip, z[1])
} else {
require.Fail(t, "Invalid enum format")
}
}
write(t, out, "\n")
} else {
if d := el.Default; d != nil {
write(t, out, "Default Value: `%s`\n\n", *d)
writef(t, out, "Default Value: `%s`\n\n", *d)
}
}

if d := el.Immutable; d != nil {
if *d == "" {
write(t, out, "This field is **immutable**\n\n")
} else {
write(t, out, "This field is **immutable**: %s\n\n", *d)
writef(t, out, "This field is **immutable**: %s\n\n", *d)
}
}
}
Expand Down Expand Up @@ -545,10 +545,10 @@ func generateDocs(t *testing.T, objects map[string]map[string]interface{}, field
"title": objName,
"parent": apiIndexPageTitle,
})
write(t, out, "# API Reference for %s\n\n", objName)
writef(t, out, "# API Reference for %s\n\n", objName)

util.IterateSorted(renderSections, func(name string, section []byte) {
write(t, out, "## %s\n\n", util.BoolSwitch(name == "", "Object", name))
writef(t, out, "## %s\n\n", util.BoolSwitch(name == "", "Object", name))

_, err = out.Write(section)
require.NoError(t, err)
Expand All @@ -558,7 +558,12 @@ func generateDocs(t *testing.T, objects map[string]map[string]interface{}, field
return outPaths
}

func write(t *testing.T, out io.Writer, format string, args ...interface{}) {
func write(t *testing.T, out io.Writer, format string) {
_, err := out.Write([]byte(format))
require.NoError(t, err)
}

func writef(t *testing.T, out io.Writer, format string, args ...interface{}) {
_, err := out.Write([]byte(fmt.Sprintf(format, args...)))
require.NoError(t, err)
}
Expand Down
24 changes: 24 additions & 0 deletions internal/readme_cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,30 @@ func GenerateCLIArangoDBOperatorPlatformReadme(root string) error {
readmeSections["arangodb_operator_platform_cmd"] = section
}

if section, err := GenerateHelpQuoted(cmd, "license"); err != nil {
return err
} else {
readmeSections["arangodb_operator_platform_license_cmd"] = section
}

if section, err := GenerateHelpQuoted(cmd, "license", "activate"); err != nil {
return err
} else {
readmeSections["arangodb_operator_platform_license_activate_cmd"] = section
}

if section, err := GenerateHelpQuoted(cmd, "license", "generate"); err != nil {
return err
} else {
readmeSections["arangodb_operator_platform_license_generate_cmd"] = section
}

if section, err := GenerateHelpQuoted(cmd, "license", "secret"); err != nil {
return err
} else {
readmeSections["arangodb_operator_platform_license_secret_cmd"] = section
}

if section, err := GenerateHelpQuoted(cmd, "package"); err != nil {
return err
} else {
Expand Down
100 changes: 100 additions & 0 deletions pkg/license/manager/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
//
// DISCLAIMER
//
// Copyright 2025 ArangoDB GmbH, Cologne, Germany
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//

package manager

import (
"context"
"fmt"
goHttp "net/http"
"time"

"github.com/arangodb/go-driver"
"github.com/arangodb/go-driver/http"

"github.com/arangodb/kube-arangodb/pkg/platform/inventory"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/arangod"
ugrpc "github.com/arangodb/kube-arangodb/pkg/util/grpc"
operatorHTTP "github.com/arangodb/kube-arangodb/pkg/util/http"
)

func NewClient(endpoint, id, key string, mods ...util.Mod[goHttp.Transport]) (Client, error) {
transport := operatorHTTP.Transport(mods...)

stageEndpoint := fmt.Sprintf("https://%s", endpoint)

connConfig := http.ConnectionConfig{
Transport: transport,
DontFollowRedirect: true,
Endpoints: []string{stageEndpoint},
}

conn, err := http.NewConnection(connConfig)
if err != nil {
return nil, err
}

conn, err = conn.SetAuthentication(driver.BasicAuthentication(id, key))
if err != nil {
return nil, err
}

return NewClientFromConn(conn), nil
}

func NewClientFromConn(conn driver.Connection) Client {
return client{
conn: conn,
}
}

type Client interface {
License(ctx context.Context, req LicenseRequest) (LicenseResponse, error)

Registry(ctx context.Context) (RegistryResponse, error)
}

type LicenseRequest struct {
DeploymentID *string `json:"deployment_id,omitempty"`
TTL *time.Duration `json:"ttl,omitempty"`
Inventory *ugrpc.Object[*inventory.Spec] `json:"inventory,omitempty"`
}

type LicenseResponse struct {
ID string `json:"id"`
License string `json:"license"`
}

type RegistryResponse struct {
Token string `json:"token"`
}

type client struct {
conn driver.Connection
}

func (c client) License(ctx context.Context, req LicenseRequest) (LicenseResponse, error) {
return arangod.PostRequest[LicenseRequest, LicenseResponse](ctx, c.conn, req, "_api", "v1", "license").AcceptCode(200).Response()
}

func (c client) Registry(ctx context.Context) (RegistryResponse, error) {
return arangod.GetRequest[RegistryResponse](ctx, c.conn, "_api", "v1", "registry", "token").AcceptCode(200).Response()
}
Loading