Skip to content

Commit

Permalink
Merge pull request #307 from arangodb/feature/license-key
Browse files Browse the repository at this point in the history
License Key
  • Loading branch information
neunhoef authored Dec 5, 2018
2 parents fb851e3 + ae3190b commit 38dcb31
Show file tree
Hide file tree
Showing 29 changed files with 360 additions and 107 deletions.
7 changes: 6 additions & 1 deletion Jenkinsfile.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,16 @@ def buildTestSteps(Map myParams, String kubeConfigRoot, String kubeconfig) {
return {
timestamps {
timeout(time: myParams.LONG ? 180 : 30) {
withCredentials([string(credentialsId: 'ENTERPRISEIMAGE', variable: 'DEFAULTENTERPRISEIMAGE')]) {
withCredentials([
string(credentialsId: 'ENTERPRISEIMAGE', variable: 'DEFAULTENTERPRISEIMAGE'),
string(credentialsId: 'ENTERPRISELICENSE', variable: 'DEFAULTENTERPRISELICENSE'),
]) {
withEnv([
"CLEANDEPLOYMENTS=1",
"DEPLOYMENTNAMESPACE=${myParams.TESTNAMESPACE}-${env.GIT_COMMIT}",
"DOCKERNAMESPACE=${myParams.DOCKERNAMESPACE}",
"ENTERPRISEIMAGE=${myParams.ENTERPRISEIMAGE}",
"ENTERPRISELICENSE=${myParams.ENTERPRISELICENSE}",
"ARANGODIMAGE=${myParams.ARANGODIMAGE}",
"IMAGETAG=jenkins-test",
"KUBECONFIG=${kubeConfigRoot}/${kubeconfig}",
Expand Down Expand Up @@ -132,6 +136,7 @@ pipeline {
string(name: 'TESTNAMESPACE', defaultValue: 'jenkins', description: 'TESTNAMESPACE sets the kubernetes namespace to ru tests in (this must be short!!)', )
string(name: 'ENTERPRISEIMAGE', defaultValue: '', description: 'ENTERPRISEIMAGE sets the docker image used for enterprise tests', )
string(name: 'ARANGODIMAGE', defaultValue: '', description: 'ARANGODIMAGE sets the docker image used for tests (except enterprise and update tests)', )
string(name: 'ENTERPRISELICENSE', defaultValue: '', description: 'ENTERPRISELICENSE sets the enterprise license key for enterprise tests', )
string(name: 'TESTOPTIONS', defaultValue: '', description: 'TESTOPTIONS is used to pass additional test options to the integration test', )
}
stages {
Expand Down
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ endif
ifndef ENTERPRISEIMAGE
ENTERPRISEIMAGE := $(DEFAULTENTERPRISEIMAGE)
endif
ifndef ENTERPRISELICENSE
ENTERPRISELICENSE := $(DEFAULTENTERPRISELICENSE)
endif
DASHBOARDBUILDIMAGE := kube-arangodb-dashboard-builder

ifndef ALLOWCHAOS
Expand Down Expand Up @@ -307,7 +310,8 @@ endif
kubectl apply -f $(MANIFESTPATHDEPLOYMENTREPLICATION)
kubectl apply -f $(MANIFESTPATHTEST)
$(ROOTDIR)/scripts/kube_create_storage.sh $(DEPLOYMENTNAMESPACE)
$(ROOTDIR)/scripts/kube_run_tests.sh $(DEPLOYMENTNAMESPACE) $(TESTIMAGE) "$(ARANGODIMAGE)" "$(ENTERPRISEIMAGE)" $(TESTTIMEOUT) $(TESTLENGTHOPTIONS)
$(ROOTDIR)/scripts/kube_create_license_key_secret.sh "$(DEPLOYMENTNAMESPACE)" '$(ENTERPRISELICENSE)'
$(ROOTDIR)/scripts/kube_run_tests.sh $(DEPLOYMENTNAMESPACE) $(TESTIMAGE) "$(ARANGODIMAGE)" '$(ENTERPRISEIMAGE)' $(TESTTIMEOUT) $(TESTLENGTHOPTIONS)

$(DURATIONTESTBIN): $(GOBUILDDIR) $(SOURCES)
@mkdir -p $(BINDIR)
Expand Down
130 changes: 65 additions & 65 deletions dashboard/assets.go

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions docs/Manual/Deployment/Kubernetes/DeploymentResource.md
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,12 @@ The default is `false`.

This setting cannot be changed after the deployment has been created.

### `spec.license.secretName: string`

This setting specifies the name of a kubernetes `Secret` that contains
the license key token used for enterprise images. This value is not used for
the community edition.

### `spec.<group>.count: number`

This setting specifies the number of servers to start for the given group.
Expand Down
5 changes: 5 additions & 0 deletions pkg/apis/deployment/v1alpha/deployment_spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ type DeploymentSpec struct {
Authentication AuthenticationSpec `json:"auth"`
TLS TLSSpec `json:"tls"`
Sync SyncSpec `json:"sync"`
License LicenseSpec `json:"license"`

Single ServerGroupSpec `json:"single"`
Agents ServerGroupSpec `json:"agents"`
Expand Down Expand Up @@ -204,6 +205,7 @@ func (s *DeploymentSpec) SetDefaultsFrom(source DeploymentSpec) {
if s.DisableIPv6 == nil {
s.DisableIPv6 = util.NewBoolOrNil(source.DisableIPv6)
}
s.License.SetDefaultsFrom(source.License)
s.ExternalAccess.SetDefaultsFrom(source.ExternalAccess)
s.RocksDB.SetDefaultsFrom(source.RocksDB)
s.Authentication.SetDefaultsFrom(source.Authentication)
Expand Down Expand Up @@ -272,6 +274,9 @@ func (s *DeploymentSpec) Validate() error {
if err := s.Chaos.Validate(); err != nil {
return maskAny(errors.Wrap(err, "spec.chaos"))
}
if err := s.License.Validate(); err != nil {
return maskAny(errors.Wrap(err, "spec.licenseKey"))
}
return nil
}

Expand Down
63 changes: 63 additions & 0 deletions pkg/apis/deployment/v1alpha/license_spec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//
// DISCLAIMER
//
// Copyright 2018 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 v1alpha

import (
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
)

// LicenseSpec holds the license related information
type LicenseSpec struct {
SecretName *string `json:"secretName,omitempty"`
}

// HasSecretName returns true if a license key secret name was set
func (s LicenseSpec) HasSecretName() bool {
return s.SecretName != nil
}

// GetSecretName returns the license key if set. Empty string otherwise.
func (s LicenseSpec) GetSecretName() string {
if s.HasSecretName() {
return *s.SecretName
}

return ""
}

// Validate validates the LicenseSpec
func (s LicenseSpec) Validate() error {
if s.HasSecretName() {
if err := k8sutil.ValidateResourceName(s.GetSecretName()); err != nil {
return err
}
}

return nil
}

// SetDefaultsFrom fills all values not set in s with values from other
func (s LicenseSpec) SetDefaultsFrom(other LicenseSpec) {
if !s.HasSecretName() {
s.SecretName = util.NewStringOrNil(other.SecretName)
}
}
15 changes: 15 additions & 0 deletions pkg/apis/deployment/v1alpha/license_spec_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package v1alpha

import (
"testing"

"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/stretchr/testify/assert"
)

func TestLicenseSpecValidation(t *testing.T) {
assert.Nil(t, LicenseSpec{SecretName: nil}.Validate())
assert.Nil(t, LicenseSpec{SecretName: util.NewString("some-name")}.Validate())

assert.Error(t, LicenseSpec{SecretName: util.NewString("@@")}.Validate())
}
22 changes: 22 additions & 0 deletions pkg/apis/deployment/v1alpha/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions pkg/deployment/context_impl.go
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,6 @@ func (d *Deployment) DeleteSecret(secretName string) error {

// GetExpectedPodArguments creates command line arguments for a server in the given group with given ID.
func (d *Deployment) GetExpectedPodArguments(apiObject metav1.Object, deplSpec api.DeploymentSpec, group api.ServerGroup,
agents api.MemberStatusList, id string) []string {
return d.resources.GetExpectedPodArguments(apiObject, deplSpec, group, agents, id)
agents api.MemberStatusList, id string, version driver.Version) []string {
return d.resources.GetExpectedPodArguments(apiObject, deplSpec, group, agents, id, version)
}
6 changes: 6 additions & 0 deletions pkg/deployment/deployment_inspector.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ func (d *Deployment) inspectDeployment(lastInterval util.Interval) util.Interval
d.CreateEvent(k8sutil.NewErrorEvent("Secret hash validation failed", err, d.apiObject))
}

// Check for LicenseKeySecret
if err := d.resources.ValidateLicenseKeySecret(); err != nil {
hasError = true
d.CreateEvent(k8sutil.NewErrorEvent("License Key Secret invalid", err, d.apiObject))
}

// Is the deployment in a good state?
status, _ := d.GetStatus()
if status.Conditions.IsTrue(api.ConditionTypeSecretsChanged) {
Expand Down
21 changes: 20 additions & 1 deletion pkg/deployment/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (

api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1alpha"
"github.com/arangodb/kube-arangodb/pkg/util/arangod"
"github.com/arangodb/kube-arangodb/pkg/util/constants"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
)

Expand Down Expand Up @@ -111,10 +112,21 @@ func (ib *imagesBuilder) fetchArangoDBImageIDAndVersion(ctx context.Context, ima
// Check if pod exists
if pod, err := ib.KubeCli.CoreV1().Pods(ns).Get(podName, metav1.GetOptions{}); err == nil {
// Pod found
if k8sutil.IsPodFailed(pod) {
// Wait some time before deleting the pod
if time.Now().After(pod.GetCreationTimestamp().Add(30 * time.Second)) {
if err := ib.KubeCli.CoreV1().Pods(ns).Delete(podName, nil); err != nil && !k8sutil.IsNotFound(err) {
log.Warn().Err(err).Msg("Failed to delete Image ID Pod")
return false, nil
}
}
return false, nil
}
if !k8sutil.IsPodReady(pod) {
log.Debug().Msg("Image ID Pod is not yet ready")
return true, nil
}

if len(pod.Status.ContainerStatuses) == 0 {
log.Warn().Msg("Empty list of ContainerStatuses")
return true, nil
Expand Down Expand Up @@ -178,7 +190,14 @@ func (ib *imagesBuilder) fetchArangoDBImageIDAndVersion(ctx context.Context, ima
tolerations = k8sutil.AddTolerationIfNotFound(tolerations, k8sutil.NewNoExecuteToleration(k8sutil.TolerationKeyNodeAlphaUnreachable, shortDur))
serviceAccountName := ""

if err := k8sutil.CreateArangodPod(ib.KubeCli, true, ib.APIObject, role, id, podName, "", image, "", "", ib.Spec.GetImagePullPolicy(), "", false, terminationGracePeriod, args, nil, nil, nil, nil,
env := make(map[string]k8sutil.EnvValue)
if ib.Spec.License.HasSecretName() {
env[constants.EnvArangoLicenseKey] = k8sutil.EnvValue{
SecretName: ib.Spec.License.GetSecretName(),
SecretKey: constants.SecretKeyToken,
}
}
if err := k8sutil.CreateArangodPod(ib.KubeCli, true, ib.APIObject, role, id, podName, "", image, "", "", ib.Spec.GetImagePullPolicy(), "", false, terminationGracePeriod, args, env, nil, nil, nil,
tolerations, serviceAccountName, "", ""); err != nil {
log.Debug().Err(err).Msg("Failed to create image ID pod")
return true, maskAny(err)
Expand Down
2 changes: 1 addition & 1 deletion pkg/deployment/reconcile/action_cleanout_member.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func (a *actionCleanoutMember) CheckProgress(ctx context.Context) (bool, bool, e
}
// do not try to clean out a pod that was not initialized
if !m.IsInitialized {
return false, true, nil
return true, false, nil
}
c, err := a.actionCtx.GetDatabaseClient(ctx)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/deployment/reconcile/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,5 +92,5 @@ type Context interface {
DeleteSecret(secretName string) error
// GetExpectedPodArguments creates command line arguments for a server in the given group with given ID.
GetExpectedPodArguments(apiObject metav1.Object, deplSpec api.DeploymentSpec, group api.ServerGroup,
agents api.MemberStatusList, id string) []string
agents api.MemberStatusList, id string, version driver.Version) []string
}
11 changes: 8 additions & 3 deletions pkg/deployment/reconcile/plan_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ func createPlan(log zerolog.Logger, apiObject k8sutil.APIObject,
newPlan = createUpgradeMemberPlan(log, m, group, "Version upgrade", spec.GetImage(), status)
} else {
// Upgrade is not needed, see if rotation is needed
if rotNeeded, reason := podNeedsRotation(log, *p, apiObject, spec, group, status.Members.Agents, m.ID, context); rotNeeded {
if rotNeeded, reason := podNeedsRotation(log, *p, apiObject, spec, group, status, m.ID, context); rotNeeded {
newPlan = createRotateMemberPlan(log, m, group, reason)
}
}
Expand Down Expand Up @@ -305,7 +305,7 @@ func podNeedsUpgrading(p v1.Pod, spec api.DeploymentSpec, images api.ImageInfoLi
// given deployment spec.
// When true is returned, a reason for the rotation is already returned.
func podNeedsRotation(log zerolog.Logger, p v1.Pod, apiObject metav1.Object, spec api.DeploymentSpec,
group api.ServerGroup, agents api.MemberStatusList, id string,
group api.ServerGroup, status api.DeploymentStatus, id string,
context PlanBuilderContext) (bool, string) {
groupSpec := spec.GetServerGroupSpec(group)

Expand All @@ -319,8 +319,13 @@ func podNeedsRotation(log zerolog.Logger, p v1.Pod, apiObject metav1.Object, spe
return true, "Server container not found"
}

podImageInfo, found := status.Images.GetByImageID(c.Image)
if !found {
return false, "Server Image not found"
}

// Check arguments
expectedArgs := strings.Join(context.GetExpectedPodArguments(apiObject, spec, group, agents, id), " ")
expectedArgs := strings.Join(context.GetExpectedPodArguments(apiObject, spec, group, status.Members.Agents, id, podImageInfo.ArangoDBVersion), " ")
actualArgs := strings.Join(getContainerArgs(c), " ")
if expectedArgs != actualArgs {
log.Debug().
Expand Down
3 changes: 2 additions & 1 deletion pkg/deployment/reconcile/plan_builder_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
package reconcile

import (
driver "github.com/arangodb/go-driver"
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1alpha"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
"k8s.io/api/core/v1"
Expand All @@ -44,7 +45,7 @@ type PlanBuilderContext interface {
GetPvc(pvcName string) (*v1.PersistentVolumeClaim, error)
// GetExpectedPodArguments creates command line arguments for a server in the given group with given ID.
GetExpectedPodArguments(apiObject metav1.Object, deplSpec api.DeploymentSpec, group api.ServerGroup,
agents api.MemberStatusList, id string) []string
agents api.MemberStatusList, id string, version driver.Version) []string
}

// newPlanBuilderContext creates a PlanBuilderContext from the given context
Expand Down
3 changes: 2 additions & 1 deletion pkg/deployment/reconcile/plan_builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

driver "github.com/arangodb/go-driver"
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1alpha"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
Expand Down Expand Up @@ -64,7 +65,7 @@ func (c *testContext) GetPvc(pvcName string) (*v1.PersistentVolumeClaim, error)

// GetExpectedPodArguments creates command line arguments for a server in the given group with given ID.
func (c *testContext) GetExpectedPodArguments(apiObject metav1.Object, deplSpec api.DeploymentSpec, group api.ServerGroup,
agents api.MemberStatusList, id string) []string {
agents api.MemberStatusList, id string, version driver.Version) []string {
return nil // not implemented
}

Expand Down
Loading

0 comments on commit 38dcb31

Please sign in to comment.