mirror of
https://github.com/arangodb/kube-arangodb.git
synced 2024-12-14 11:57:37 +00:00
[Feature] License ArangoDeployment Fetcher (#1485)
This commit is contained in:
parent
828350d86a
commit
5ebc821941
12 changed files with 122 additions and 388 deletions
|
@ -8,6 +8,7 @@
|
|||
- (Bugfix) Proper handling of --agency.retries argument
|
||||
- (Documentation) Do not use field type name for field URL hash
|
||||
- (Maintenance) Bump Go to 1.20.11
|
||||
- (Feature) License ArangoDeployment Fetcher
|
||||
|
||||
## [1.2.35](https://github.com/arangodb/kube-arangodb/tree/1.2.35) (2023-11-06)
|
||||
- (Maintenance) Update go-driver to v1.6.0, update IsNotFound() checks
|
||||
|
|
10
cmd/cmd.go
10
cmd/cmd.go
|
@ -52,7 +52,6 @@ import (
|
|||
"github.com/arangodb/kube-arangodb/pkg/deployment/features"
|
||||
"github.com/arangodb/kube-arangodb/pkg/deployment/reconcile"
|
||||
"github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned/scheme"
|
||||
"github.com/arangodb/kube-arangodb/pkg/license"
|
||||
"github.com/arangodb/kube-arangodb/pkg/logging"
|
||||
"github.com/arangodb/kube-arangodb/pkg/metrics/collector"
|
||||
"github.com/arangodb/kube-arangodb/pkg/operator"
|
||||
|
@ -172,8 +171,6 @@ var (
|
|||
backupProbe probe.ReadyProbe
|
||||
appsProbe probe.ReadyProbe
|
||||
k2KClusterSyncProbe probe.ReadyProbe
|
||||
|
||||
licenseConfig license.Config
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
@ -239,9 +236,6 @@ func init() {
|
|||
if err := reconcile.ActionsConfigGlobal.Init(&cmdMain); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
if err := licenseConfig.Init(&cmdMain); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func Execute() int {
|
||||
|
@ -315,10 +309,6 @@ func executeMain(cmd *cobra.Command, args []string) {
|
|||
})
|
||||
}
|
||||
|
||||
if err := licenseConfig.Enable(); err != nil {
|
||||
logger.Err(err).Fatal("Failed to License checker process")
|
||||
}
|
||||
|
||||
logger.Info("nice to meet you")
|
||||
|
||||
// Print all enabled featured
|
||||
|
|
|
@ -1,91 +0,0 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2023 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 license
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/kclient"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Enabled bool
|
||||
|
||||
Secret struct {
|
||||
Namespace, Name, Key, ClientFactory string
|
||||
}
|
||||
|
||||
Env struct {
|
||||
Env string
|
||||
}
|
||||
|
||||
Type string
|
||||
|
||||
RefreshInterval time.Duration
|
||||
RefreshTimeout time.Duration
|
||||
}
|
||||
|
||||
func (c *Config) Init(cmd *cobra.Command) error {
|
||||
f := cmd.PersistentFlags()
|
||||
|
||||
f.BoolVar(&c.Enabled, "license.enabled", true, "Define if LicenseManager is enabled")
|
||||
f.StringVar(&c.Type, "license.type", "secret", "Define type of the license fetch, possible values are secret or env")
|
||||
f.StringVar(&c.Secret.Namespace, "license.secret.namespace", "", "Define Secret Namespace for the Secret type of LicenseManager")
|
||||
f.StringVar(&c.Secret.Name, "license.secret.name", "", "Define Secret Name for the Secret type of LicenseManager")
|
||||
f.StringVar(&c.Secret.Key, "license.secret.key", "license", "Define Secret Key for the Secret type of LicenseManager")
|
||||
f.StringVar(&c.Secret.ClientFactory, "license.secret.client-factory", "", "Define K8S Client Factory for the Secret type of LicenseManager")
|
||||
f.StringVar(&c.Env.Env, "license.env.name", "ARANGODB_LICENSE", "Define Environment Variable name for the Env type of LicenseManager")
|
||||
f.DurationVar(&c.RefreshInterval, "license.refresh.interval", 30*time.Second, "Refresh interval for LicenseManager")
|
||||
f.DurationVar(&c.RefreshTimeout, "license.refresh.timeout", 3*time.Second, "Refresh timeout for LicenseManager")
|
||||
|
||||
if err := f.MarkHidden("license.enabled"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := f.MarkHidden("license.secret.client-factory"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c Config) Enable() error {
|
||||
if !c.Enabled {
|
||||
return initManager(c, NewDisabledLoader())
|
||||
}
|
||||
|
||||
switch c.Type {
|
||||
case "secret":
|
||||
return initManager(c, NewSecretLoader(kclient.GetFactory(c.Secret.ClientFactory), c.Secret.Namespace, c.Secret.Name, c.Secret.Key))
|
||||
|
||||
case "env":
|
||||
if l, ok := os.LookupEnv(c.Env.Env); ok {
|
||||
return initManager(c, NewConstantLoader(l))
|
||||
}
|
||||
|
||||
return initManager(c, NewDisabledLoader())
|
||||
default:
|
||||
return errors.Newf("Unsupported type for license.type: %s", c.Type)
|
||||
}
|
||||
}
|
|
@ -20,15 +20,23 @@
|
|||
|
||||
package license
|
||||
|
||||
import "github.com/arangodb/kube-arangodb/pkg/util/assertion"
|
||||
import (
|
||||
"context"
|
||||
|
||||
func checkLicense(license string) License {
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/assertion"
|
||||
)
|
||||
|
||||
func NewLicense(loader Loader) License {
|
||||
return emptyLicense{}
|
||||
}
|
||||
|
||||
type emptyLicense struct {
|
||||
}
|
||||
|
||||
func (e emptyLicense) Refresh(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate for the community returns that license is always missing, as it should be not used
|
||||
func (e emptyLicense) Validate(feature Feature, subFeatures ...Feature) Status {
|
||||
assertion.Assert(true, assertion.CommunityLicenseCheckKey, "Feature %s has been validated in the community version", feature)
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
|
||||
package license
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type Status int
|
||||
|
||||
const (
|
||||
|
@ -79,4 +83,6 @@ type License interface {
|
|||
// -- for each subFeature defined in subFeatures:
|
||||
// --- checks if subFeature or '*' is in the list of License Feature enabled SubFeatures
|
||||
Validate(feature Feature, subFeatures ...Feature) Status
|
||||
|
||||
Refresh(ctx context.Context) error
|
||||
}
|
||||
|
|
101
pkg/license/loader_arangodeployment.go
Normal file
101
pkg/license/loader_arangodeployment.go
Normal file
|
@ -0,0 +1,101 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2023 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 license
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/constants"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/kclient"
|
||||
)
|
||||
|
||||
func NewArengoDeploymentLicenseLoader(factory kclient.Factory, namespace, name string) Loader {
|
||||
return arangoDeploymentLicenseLoader{
|
||||
factory: factory,
|
||||
namespace: namespace,
|
||||
name: name,
|
||||
}
|
||||
}
|
||||
|
||||
type arangoDeploymentLicenseLoader struct {
|
||||
factory kclient.Factory
|
||||
|
||||
namespace, name string
|
||||
}
|
||||
|
||||
func (a arangoDeploymentLicenseLoader) Refresh(ctx context.Context) (string, bool, error) {
|
||||
client, ok := a.factory.Client()
|
||||
if !ok {
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
deployment, err := client.Arango().DatabaseV1().ArangoDeployments(a.namespace).Get(ctx, a.name, meta.GetOptions{})
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
return "", false, err
|
||||
}
|
||||
|
||||
spec := deployment.GetAcceptedSpec()
|
||||
|
||||
if !spec.License.HasSecretName() {
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
secret, err := client.Kubernetes().CoreV1().Secrets(deployment.GetNamespace()).Get(ctx, spec.License.GetSecretName(), meta.GetOptions{})
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
return "", false, err
|
||||
}
|
||||
|
||||
var licenseData []byte
|
||||
|
||||
if lic, ok := secret.Data[constants.SecretKeyV2License]; ok {
|
||||
licenseData = lic
|
||||
} else if lic2, ok := secret.Data[constants.SecretKeyV2Token]; ok {
|
||||
licenseData = lic2
|
||||
}
|
||||
|
||||
if len(licenseData) == 0 {
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
if !k8sutil.IsJSON(licenseData) {
|
||||
d, err := base64.StdEncoding.DecodeString(string(licenseData))
|
||||
if err != nil {
|
||||
return "", false, err
|
||||
}
|
||||
|
||||
licenseData = d
|
||||
}
|
||||
|
||||
return string(licenseData), true, nil
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2023 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 license
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
func NewConstantLoader(license string) Loader {
|
||||
return loaderConstant(license)
|
||||
}
|
||||
|
||||
type loaderConstant string
|
||||
|
||||
func (l loaderConstant) Refresh(ctx context.Context) (string, bool, error) {
|
||||
return string(l), false, nil
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2023 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 license
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
func NewDisabledLoader() Loader {
|
||||
return loaderDisabled{}
|
||||
}
|
||||
|
||||
type loaderDisabled struct {
|
||||
}
|
||||
|
||||
func (l loaderDisabled) Refresh(ctx context.Context) (string, bool, error) {
|
||||
return "", false, nil
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2023 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 license
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
errors2 "github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/kclient"
|
||||
)
|
||||
|
||||
func NewSecretLoader(factory kclient.Factory, namespace, name, key string) Loader {
|
||||
return secretLoader{
|
||||
factory: factory,
|
||||
namespace: namespace,
|
||||
name: name,
|
||||
key: key,
|
||||
}
|
||||
}
|
||||
|
||||
type secretLoader struct {
|
||||
factory kclient.Factory
|
||||
namespace, name, key string
|
||||
}
|
||||
|
||||
func (s secretLoader) Refresh(ctx context.Context) (string, bool, error) {
|
||||
client, ok := s.factory.Client()
|
||||
if !ok {
|
||||
return "", false, errors2.Newf("Client is not yet ready")
|
||||
}
|
||||
|
||||
secret, err := client.Kubernetes().CoreV1().Secrets(s.namespace).Get(ctx, s.name, meta.GetOptions{})
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
return "", false, err
|
||||
}
|
||||
|
||||
if len(secret.Data) == 0 {
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
license, ok := secret.Data[s.key]
|
||||
if !ok {
|
||||
return "", false, nil
|
||||
}
|
||||
|
||||
return string(license), true, nil
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2023 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 license
|
||||
|
||||
import "github.com/arangodb/kube-arangodb/pkg/logging"
|
||||
|
||||
var (
|
||||
logger = logging.Global().RegisterAndGetLogger("license", logging.Info)
|
||||
)
|
|
@ -1,111 +0,0 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2023 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 license
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/errors"
|
||||
"github.com/arangodb/kube-arangodb/pkg/util/shutdown"
|
||||
)
|
||||
|
||||
var (
|
||||
lock sync.Mutex
|
||||
managerInstance Manager
|
||||
)
|
||||
|
||||
func initManager(config Config, loader Loader) error {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
if managerInstance != nil {
|
||||
return errors.Newf("Manager is already initialised")
|
||||
}
|
||||
|
||||
mgr := &manager{
|
||||
loader: loader,
|
||||
config: config,
|
||||
license: StatusMissing,
|
||||
}
|
||||
|
||||
go mgr.run(shutdown.Channel())
|
||||
|
||||
managerInstance = mgr
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func ManagerInstance() Manager {
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
if managerInstance == nil {
|
||||
panic("Manager not yet initialised")
|
||||
}
|
||||
|
||||
return managerInstance
|
||||
}
|
||||
|
||||
type Manager interface {
|
||||
}
|
||||
|
||||
type manager struct {
|
||||
config Config
|
||||
loader Loader
|
||||
|
||||
license License
|
||||
}
|
||||
|
||||
func (m *manager) run(stopC <-chan struct{}) {
|
||||
t := time.NewTicker(m.config.RefreshInterval)
|
||||
defer t.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-stopC:
|
||||
return
|
||||
case <-t.C:
|
||||
// Lets do the refresh
|
||||
logger.Debug("Refresh process started")
|
||||
|
||||
license, ok, err := m.loadLicense()
|
||||
if err != nil {
|
||||
logger.Err(err).Warn("Unable to load license")
|
||||
continue
|
||||
}
|
||||
|
||||
if !ok {
|
||||
logger.Debug("License is missing")
|
||||
continue
|
||||
}
|
||||
|
||||
m.license = checkLicense(license)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *manager) loadLicense() (string, bool, error) {
|
||||
ctx, c := context.WithTimeout(context.Background(), m.config.RefreshTimeout)
|
||||
defer c()
|
||||
return m.loader.Refresh(ctx)
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
//
|
||||
// DISCLAIMER
|
||||
//
|
||||
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany
|
||||
// Copyright 2016-2023 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.
|
||||
|
@ -59,14 +59,14 @@ func GetLicenseFromSecret(secret secret.Inspector, name string) (LicenseSecret,
|
|||
|
||||
if v1, ok1 := s.Data[constants.SecretKeyV2License]; ok1 {
|
||||
// some customers put the raw JSON-encoded value, but operator and DB servers expect the base64-encoded value
|
||||
if isJSONBytes(v1) {
|
||||
if IsJSON(v1) {
|
||||
l.V2 = License(base64.StdEncoding.EncodeToString(v1))
|
||||
} else {
|
||||
l.V2 = License(v1)
|
||||
}
|
||||
} else if v2, ok2 := s.Data[constants.SecretKeyV2Token]; ok2 {
|
||||
// some customers put the raw JSON-encoded value, but operator and DB servers expect the base64-encoded value
|
||||
if isJSONBytes(v2) {
|
||||
if IsJSON(v2) {
|
||||
l.V2 = License(base64.StdEncoding.EncodeToString(v2))
|
||||
} else {
|
||||
l.V2 = License(v2)
|
||||
|
@ -79,7 +79,7 @@ func GetLicenseFromSecret(secret secret.Inspector, name string) (LicenseSecret,
|
|||
return l, nil
|
||||
}
|
||||
|
||||
func isJSONBytes(s []byte) bool {
|
||||
func IsJSON(s []byte) bool {
|
||||
var js json.RawMessage
|
||||
return json.Unmarshal(s, &js) == nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue