1
0
Fork 0
mirror of https://github.com/arangodb/kube-arangodb.git synced 2024-12-14 11:57:37 +00:00

Using refs in the spec as much as possible to detect unspecified fields

This commit is contained in:
Ewout Prangsma 2018-03-22 17:31:13 +01:00
parent f49f621fc0
commit 1563e9a66a
No known key found for this signature in database
GPG key ID: 4DBAD380D93D0698
23 changed files with 444 additions and 145 deletions

View file

@ -25,12 +25,13 @@ package v1alpha
import (
"github.com/pkg/errors"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
)
// AuthenticationSpec holds authentication specific configuration settings
type AuthenticationSpec struct {
JWTSecretName string `json:"jwtSecretName,omitempty"`
JWTSecretName *string `json:"jwtSecretName,omitempty"`
}
const (
@ -38,10 +39,18 @@ const (
JWTSecretNameDisabled = "None"
)
// GetJWTSecretName returns the value of jwtSecretName.
func (s AuthenticationSpec) GetJWTSecretName() string {
if s.JWTSecretName == nil {
return ""
}
return *s.JWTSecretName
}
// IsAuthenticated returns true if authentication is enabled.
// Returns false other (when JWTSecretName == "None").
func (s AuthenticationSpec) IsAuthenticated() bool {
return s.JWTSecretName != JWTSecretNameDisabled
return s.GetJWTSecretName() != JWTSecretNameDisabled
}
// Validate the given spec
@ -50,7 +59,7 @@ func (s AuthenticationSpec) Validate(required bool) error {
return maskAny(errors.Wrap(ValidationError, "JWT secret is required"))
}
if s.IsAuthenticated() {
if err := k8sutil.ValidateResourceName(s.JWTSecretName); err != nil {
if err := k8sutil.ValidateResourceName(s.GetJWTSecretName()); err != nil {
return maskAny(err)
}
}
@ -59,8 +68,17 @@ func (s AuthenticationSpec) Validate(required bool) error {
// SetDefaults fills in missing defaults
func (s *AuthenticationSpec) SetDefaults(defaultJWTSecretName string) {
if s.JWTSecretName == "" {
s.JWTSecretName = defaultJWTSecretName
if s.GetJWTSecretName() == "" {
// Note that we don't check for nil here, since even a specified, but empty
// string should result in the default value.
s.JWTSecretName = util.String(defaultJWTSecretName)
}
}
// SetDefaultsFrom fills unspecified fields with a value from given source spec.
func (s *AuthenticationSpec) SetDefaultsFrom(source AuthenticationSpec) {
if s.JWTSecretName == nil {
s.JWTSecretName = util.String(source.GetJWTSecretName())
}
}
@ -71,7 +89,7 @@ func (s AuthenticationSpec) ResetImmutableFields(fieldPrefix string, target *Aut
var resetFields []string
if s.IsAuthenticated() != target.IsAuthenticated() {
// Note: You can change the name, but not from empty to non-empty (or reverse).
target.JWTSecretName = s.JWTSecretName
target.JWTSecretName = util.StringOrNil(s.JWTSecretName)
resetFields = append(resetFields, fieldPrefix+".jwtSecretName")
}
return resetFields

View file

@ -25,23 +25,24 @@ package v1alpha
import (
"testing"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/stretchr/testify/assert"
)
func TestAuthenticationSpecValidate(t *testing.T) {
// Valid
assert.Nil(t, AuthenticationSpec{JWTSecretName: "None"}.Validate(false))
assert.Nil(t, AuthenticationSpec{JWTSecretName: "foo"}.Validate(false))
assert.Nil(t, AuthenticationSpec{JWTSecretName: "foo"}.Validate(true))
assert.Nil(t, AuthenticationSpec{JWTSecretName: util.String("None")}.Validate(false))
assert.Nil(t, AuthenticationSpec{JWTSecretName: util.String("foo")}.Validate(false))
assert.Nil(t, AuthenticationSpec{JWTSecretName: util.String("foo")}.Validate(true))
// Not valid
assert.Error(t, AuthenticationSpec{JWTSecretName: "Foo"}.Validate(false))
assert.Error(t, AuthenticationSpec{JWTSecretName: util.String("Foo")}.Validate(false))
}
func TestAuthenticationSpecIsAuthenticated(t *testing.T) {
assert.False(t, AuthenticationSpec{JWTSecretName: "None"}.IsAuthenticated())
assert.True(t, AuthenticationSpec{JWTSecretName: "foo"}.IsAuthenticated())
assert.True(t, AuthenticationSpec{JWTSecretName: ""}.IsAuthenticated())
assert.False(t, AuthenticationSpec{JWTSecretName: util.String("None")}.IsAuthenticated())
assert.True(t, AuthenticationSpec{JWTSecretName: util.String("foo")}.IsAuthenticated())
assert.True(t, AuthenticationSpec{JWTSecretName: util.String("")}.IsAuthenticated())
}
func TestAuthenticationSpecSetDefaults(t *testing.T) {
@ -50,8 +51,8 @@ func TestAuthenticationSpecSetDefaults(t *testing.T) {
return spec
}
assert.Equal(t, "test-jwt", def(AuthenticationSpec{}).JWTSecretName)
assert.Equal(t, "foo", def(AuthenticationSpec{JWTSecretName: "foo"}).JWTSecretName)
assert.Equal(t, "test-jwt", def(AuthenticationSpec{}).GetJWTSecretName())
assert.Equal(t, "foo", def(AuthenticationSpec{JWTSecretName: util.String("foo")}).GetJWTSecretName())
}
func TestAuthenticationSpecResetImmutableFields(t *testing.T) {
@ -63,35 +64,35 @@ func TestAuthenticationSpecResetImmutableFields(t *testing.T) {
}{
// Valid "changes"
{
AuthenticationSpec{JWTSecretName: "None"},
AuthenticationSpec{JWTSecretName: "None"},
AuthenticationSpec{JWTSecretName: "None"},
AuthenticationSpec{JWTSecretName: util.String("None")},
AuthenticationSpec{JWTSecretName: util.String("None")},
AuthenticationSpec{JWTSecretName: util.String("None")},
nil,
},
{
AuthenticationSpec{JWTSecretName: "foo"},
AuthenticationSpec{JWTSecretName: "foo"},
AuthenticationSpec{JWTSecretName: "foo"},
AuthenticationSpec{JWTSecretName: util.String("foo")},
AuthenticationSpec{JWTSecretName: util.String("foo")},
AuthenticationSpec{JWTSecretName: util.String("foo")},
nil,
},
{
AuthenticationSpec{JWTSecretName: "foo"},
AuthenticationSpec{JWTSecretName: "foo2"},
AuthenticationSpec{JWTSecretName: "foo2"},
AuthenticationSpec{JWTSecretName: util.String("foo")},
AuthenticationSpec{JWTSecretName: util.String("foo2")},
AuthenticationSpec{JWTSecretName: util.String("foo2")},
nil,
},
// Invalid changes
{
AuthenticationSpec{JWTSecretName: "foo"},
AuthenticationSpec{JWTSecretName: "None"},
AuthenticationSpec{JWTSecretName: "foo"},
AuthenticationSpec{JWTSecretName: util.String("foo")},
AuthenticationSpec{JWTSecretName: util.String("None")},
AuthenticationSpec{JWTSecretName: util.String("foo")},
[]string{"test.jwtSecretName"},
},
{
AuthenticationSpec{JWTSecretName: "None"},
AuthenticationSpec{JWTSecretName: "foo"},
AuthenticationSpec{JWTSecretName: "None"},
AuthenticationSpec{JWTSecretName: util.String("None")},
AuthenticationSpec{JWTSecretName: util.String("foo")},
AuthenticationSpec{JWTSecretName: util.String("None")},
[]string{"test.jwtSecretName"},
},
}

View file

@ -102,6 +102,35 @@ func (s *DeploymentSpec) SetDefaults(deploymentName string) {
s.SyncWorkers.SetDefaults(ServerGroupSyncWorkers, s.Sync.Enabled, s.Mode)
}
// SetDefaultsFrom fills unspecified fields with a value from given source spec.
func (s *DeploymentSpec) SetDefaultsFrom(source DeploymentSpec) {
if s.Mode == "" {
s.Mode = source.Mode
}
if s.Environment == "" {
s.Environment = source.Environment
}
if s.StorageEngine == "" {
s.StorageEngine = source.StorageEngine
}
if s.Image == "" {
s.Image = source.Image
}
if s.ImagePullPolicy == "" {
s.ImagePullPolicy = source.ImagePullPolicy
}
s.RocksDB.SetDefaultsFrom(source.RocksDB)
s.Authentication.SetDefaultsFrom(source.Authentication)
s.TLS.SetDefaultsFrom(source.TLS)
s.Sync.SetDefaultsFrom(source.Sync)
s.Single.SetDefaultsFrom(source.Single)
s.Agents.SetDefaultsFrom(source.Agents)
s.DBServers.SetDefaultsFrom(source.DBServers)
s.Coordinators.SetDefaultsFrom(source.Coordinators)
s.SyncMasters.SetDefaultsFrom(source.SyncMasters)
s.SyncWorkers.SetDefaultsFrom(source.SyncWorkers)
}
// Validate the specification.
// Return errors when validation fails, nil on success.
func (s *DeploymentSpec) Validate() error {

View file

@ -47,4 +47,7 @@ type DeploymentStatus struct {
// Plan to update this deployment
Plan Plan `json:"plan,omitempty"`
// AcceptedSpec contains the last specification that was accepted by the operator.
AcceptedSpec *DeploymentSpec `json:"accepted-spec,omitempty"`
}

View file

@ -23,17 +23,26 @@
package v1alpha
import (
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
)
// MonitoringSpec holds monitoring specific configuration settings
type MonitoringSpec struct {
TokenSecretName string `json:"tokenSecretName,omitempty"`
TokenSecretName *string `json:"tokenSecretName,omitempty"`
}
// GetTokenSecretName returns the value of tokenSecretName.
func (s MonitoringSpec) GetTokenSecretName() string {
if s.TokenSecretName == nil {
return ""
}
return *s.TokenSecretName
}
// Validate the given spec
func (s MonitoringSpec) Validate() error {
if err := k8sutil.ValidateOptionalResourceName(s.TokenSecretName); err != nil {
if err := k8sutil.ValidateOptionalResourceName(s.GetTokenSecretName()); err != nil {
return maskAny(err)
}
return nil
@ -43,3 +52,10 @@ func (s MonitoringSpec) Validate() error {
func (s *MonitoringSpec) SetDefaults() {
// Nothing needed
}
// SetDefaultsFrom fills unspecified fields with a value from given source spec.
func (s *MonitoringSpec) SetDefaultsFrom(source MonitoringSpec) {
if s.TokenSecretName == nil {
s.TokenSecretName = util.StringOrNil(source.TokenSecretName)
}
}

View file

@ -25,17 +25,19 @@ package v1alpha
import (
"testing"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/stretchr/testify/assert"
)
func TestMonitoringSpecValidate(t *testing.T) {
// Valid
assert.Nil(t, MonitoringSpec{TokenSecretName: ""}.Validate())
assert.Nil(t, MonitoringSpec{TokenSecretName: "foo"}.Validate())
assert.Nil(t, MonitoringSpec{TokenSecretName: "foo"}.Validate())
assert.Nil(t, MonitoringSpec{TokenSecretName: nil}.Validate())
assert.Nil(t, MonitoringSpec{TokenSecretName: util.String("")}.Validate())
assert.Nil(t, MonitoringSpec{TokenSecretName: util.String("foo")}.Validate())
assert.Nil(t, MonitoringSpec{TokenSecretName: util.String("foo")}.Validate())
// Not valid
assert.Error(t, MonitoringSpec{TokenSecretName: "Foo"}.Validate())
assert.Error(t, MonitoringSpec{TokenSecretName: util.String("Foo")}.Validate())
}
func TestMonitoringSpecSetDefaults(t *testing.T) {
@ -44,6 +46,6 @@ func TestMonitoringSpecSetDefaults(t *testing.T) {
return spec
}
assert.Equal(t, "", def(MonitoringSpec{}).TokenSecretName)
assert.Equal(t, "foo", def(MonitoringSpec{TokenSecretName: "foo"}).TokenSecretName)
assert.Equal(t, "", def(MonitoringSpec{}).GetTokenSecretName())
assert.Equal(t, "foo", def(MonitoringSpec{TokenSecretName: util.String("foo")}).GetTokenSecretName())
}

View file

@ -23,12 +23,27 @@
package v1alpha
import (
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
)
// RocksDBEncryptionSpec holds rocksdb encryption at rest specific configuration settings
type RocksDBEncryptionSpec struct {
KeySecretName string `json:"keySecretName,omitempty"`
KeySecretName *string `json:"keySecretName,omitempty"`
}
// GetKeySecretName returns the value of keySecretName.
func (s RocksDBEncryptionSpec) GetKeySecretName() string {
if s.KeySecretName == nil {
return ""
}
return *s.KeySecretName
}
// IsEncrypted returns true when an encryption key secret name is provided,
// false otherwise.
func (s RocksDBEncryptionSpec) IsEncrypted() bool {
return s.GetKeySecretName() != ""
}
// RocksDBSpec holds rocksdb specific configuration settings
@ -39,12 +54,12 @@ type RocksDBSpec struct {
// IsEncrypted returns true when an encryption key secret name is provided,
// false otherwise.
func (s RocksDBSpec) IsEncrypted() bool {
return s.Encryption.KeySecretName != ""
return s.Encryption.IsEncrypted()
}
// Validate the given spec
func (s RocksDBSpec) Validate() error {
if err := k8sutil.ValidateOptionalResourceName(s.Encryption.KeySecretName); err != nil {
if err := k8sutil.ValidateOptionalResourceName(s.Encryption.GetKeySecretName()); err != nil {
return maskAny(err)
}
return nil
@ -55,6 +70,13 @@ func (s *RocksDBSpec) SetDefaults() {
// Nothing needed
}
// SetDefaultsFrom fills unspecified fields with a value from given source spec.
func (s *RocksDBSpec) SetDefaultsFrom(source RocksDBSpec) {
if s.Encryption.KeySecretName == nil {
s.Encryption.KeySecretName = util.StringOrNil(source.Encryption.KeySecretName)
}
}
// ResetImmutableFields replaces all immutable fields in the given target with values from the source spec.
// It returns a list of fields that have been reset.
// Field names are relative to given field prefix.
@ -62,7 +84,7 @@ func (s RocksDBSpec) ResetImmutableFields(fieldPrefix string, target *RocksDBSpe
var resetFields []string
if s.IsEncrypted() != target.IsEncrypted() {
// Note: You can change the name, but not from empty to non-empty (or reverse).
target.Encryption.KeySecretName = s.Encryption.KeySecretName
target.Encryption.KeySecretName = util.StringOrNil(s.Encryption.KeySecretName)
resetFields = append(resetFields, fieldPrefix+".encryption.keySecretName")
}
return resetFields

View file

@ -25,22 +25,23 @@ package v1alpha
import (
"testing"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/stretchr/testify/assert"
)
func TestRocksDBSpecValidate(t *testing.T) {
// Valid
assert.Nil(t, RocksDBSpec{}.Validate())
assert.Nil(t, RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: "foo"}}.Validate())
assert.Nil(t, RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: util.String("foo")}}.Validate())
// Not valid
assert.Error(t, RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: "Foo"}}.Validate())
assert.Error(t, RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: util.String("Foo")}}.Validate())
}
func TestRocksDBSpecIsEncrypted(t *testing.T) {
assert.False(t, RocksDBSpec{}.IsEncrypted())
assert.False(t, RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: ""}}.IsEncrypted())
assert.True(t, RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: "foo"}}.IsEncrypted())
assert.False(t, RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: util.String("")}}.IsEncrypted())
assert.True(t, RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: util.String("foo")}}.IsEncrypted())
}
func TestRocksDBSpecSetDefaults(t *testing.T) {
@ -49,7 +50,7 @@ func TestRocksDBSpecSetDefaults(t *testing.T) {
return spec
}
assert.Equal(t, "", def(RocksDBSpec{}).Encryption.KeySecretName)
assert.Equal(t, "", def(RocksDBSpec{}).Encryption.GetKeySecretName())
}
func TestRocksDBSpecResetImmutableFields(t *testing.T) {
@ -67,23 +68,23 @@ func TestRocksDBSpecResetImmutableFields(t *testing.T) {
nil,
},
{
RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: "foo"}},
RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: "foo"}},
RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: "foo"}},
RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: util.String("foo")}},
RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: util.String("foo")}},
RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: util.String("foo")}},
nil,
},
{
RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: "foo"}},
RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: "foo2"}},
RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: "foo2"}},
RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: util.String("foo")}},
RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: util.String("foo2")}},
RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: util.String("foo2")}},
nil,
},
// Invalid changes
{
RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: "foo"}},
RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: ""}},
RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: "foo"}},
RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: util.String("foo")}},
RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: util.String("")}},
RocksDBSpec{Encryption: RocksDBEncryptionSpec{KeySecretName: util.String("foo")}},
[]string{"test.encryption.keySecretName"},
},
}

View file

@ -26,20 +26,38 @@ import (
"github.com/pkg/errors"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"github.com/arangodb/kube-arangodb/pkg/util"
)
// ServerGroupSpec contains the specification for all servers in a specific group (e.g. all agents)
type ServerGroupSpec struct {
// Count holds the requested number of servers
Count int `json:"count,omitempty"`
Count *int `json:"count,omitempty"`
// Args holds additional commandline arguments
Args []string `json:"args,omitempty"`
// StorageClassName specifies the classname for storage of the servers.
StorageClassName string `json:"storageClassName,omitempty"`
StorageClassName *string `json:"storageClassName,omitempty"`
// Resources holds resource requests & limits
Resources v1.ResourceRequirements `json:"resource,omitempty"`
}
// GetCount returns the value of count.
func (s ServerGroupSpec) GetCount() int {
if s.Count == nil {
return 0
}
return *s.Count
}
// GetStorageClassName returns the value of count.
func (s ServerGroupSpec) GetStorageClassName() string {
if s.StorageClassName == nil {
return ""
}
return *s.StorageClassName
}
// Validate the given group spec
func (s ServerGroupSpec) Validate(group ServerGroup, used bool, mode DeploymentMode, env Environment) error {
if used {
@ -56,13 +74,13 @@ func (s ServerGroupSpec) Validate(group ServerGroup, used bool, mode DeploymentM
minCount = 2
}
}
if s.Count < minCount {
if s.GetCount() < minCount {
return maskAny(errors.Wrapf(ValidationError, "Invalid count value %d. Expected >= %d", s.Count, minCount))
}
if s.Count > 1 && group == ServerGroupSingle && mode == DeploymentModeSingle {
if s.GetCount() > 1 && group == ServerGroupSingle && mode == DeploymentModeSingle {
return maskAny(errors.Wrapf(ValidationError, "Invalid count value %d. Expected 1", s.Count))
}
} else if s.Count != 0 {
} else if s.GetCount() != 0 {
return maskAny(errors.Wrapf(ValidationError, "Invalid count value %d for un-used group. Expected 0", s.Count))
}
return nil
@ -70,16 +88,16 @@ func (s ServerGroupSpec) Validate(group ServerGroup, used bool, mode DeploymentM
// SetDefaults fills in missing defaults
func (s *ServerGroupSpec) SetDefaults(group ServerGroup, used bool, mode DeploymentMode) {
if s.Count == 0 && used {
if s.GetCount() == 0 && used {
switch group {
case ServerGroupSingle:
if mode == DeploymentModeSingle {
s.Count = 1 // Single server
s.Count = util.Int(1) // Single server
} else {
s.Count = 2 // Resilient single
s.Count = util.Int(2) // Resilient single
}
default:
s.Count = 3
s.Count = util.Int(3)
}
}
if _, found := s.Resources.Requests[v1.ResourceStorage]; !found {
@ -93,18 +111,32 @@ func (s *ServerGroupSpec) SetDefaults(group ServerGroup, used bool, mode Deploym
}
}
// SetDefaultsFrom fills unspecified fields with a value from given source spec.
func (s *ServerGroupSpec) SetDefaultsFrom(source ServerGroupSpec) {
if s.Count == nil {
s.Count = util.IntOrNil(source.Count)
}
if s.Args == nil {
s.Args = source.Args
}
if s.StorageClassName == nil {
s.StorageClassName = util.StringOrNil(source.StorageClassName)
}
// TODO Resources
}
// ResetImmutableFields replaces all immutable fields in the given target with values from the source spec.
// It returns a list of fields that have been reset.
func (s ServerGroupSpec) ResetImmutableFields(group ServerGroup, fieldPrefix string, target *ServerGroupSpec) []string {
var resetFields []string
if group == ServerGroupAgents {
if s.Count != target.Count {
target.Count = s.Count
if s.GetCount() != target.GetCount() {
target.Count = util.IntOrNil(s.Count)
resetFields = append(resetFields, fieldPrefix+".count")
}
}
if s.StorageClassName != target.StorageClassName {
target.StorageClassName = s.StorageClassName
if s.GetStorageClassName() != target.GetStorageClassName() {
target.StorageClassName = util.StringOrNil(s.StorageClassName)
resetFields = append(resetFields, fieldPrefix+".storageClassName")
}
return resetFields

View file

@ -73,6 +73,19 @@ func (s *SyncSpec) SetDefaults(defaultImage string, defaulPullPolicy v1.PullPoli
s.Monitoring.SetDefaults()
}
// SetDefaultsFrom fills unspecified fields with a value from given source spec.
func (s *SyncSpec) SetDefaultsFrom(source SyncSpec) {
if s.Image == "" {
s.Image = source.Image
}
if s.ImagePullPolicy == "" {
s.ImagePullPolicy = source.ImagePullPolicy
}
s.Authentication.SetDefaultsFrom(source.Authentication)
s.TLS.SetDefaultsFrom(source.TLS)
s.Monitoring.SetDefaultsFrom(source.Monitoring)
}
// ResetImmutableFields replaces all immutable fields in the given target with values from the source spec.
// It returns a list of fields that have been reset.
// Field names are relative to given field prefix.

View file

@ -25,24 +25,26 @@ package v1alpha
import (
"testing"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/stretchr/testify/assert"
"k8s.io/api/core/v1"
)
func TestSyncSpecValidate(t *testing.T) {
// Valid
auth := AuthenticationSpec{JWTSecretName: "foo"}
auth := AuthenticationSpec{JWTSecretName: util.String("foo")}
tls := TLSSpec{CASecretName: util.String("None")}
assert.Nil(t, SyncSpec{Image: "foo", Authentication: auth}.Validate(DeploymentModeSingle))
assert.Nil(t, SyncSpec{Image: "foo", Authentication: auth}.Validate(DeploymentModeResilientSingle))
assert.Nil(t, SyncSpec{Image: "foo", Authentication: auth}.Validate(DeploymentModeCluster))
assert.Nil(t, SyncSpec{Image: "foo", Authentication: auth, Enabled: true}.Validate(DeploymentModeCluster))
assert.Nil(t, SyncSpec{Image: "foo", Authentication: auth, TLS: tls, Enabled: true}.Validate(DeploymentModeCluster))
// Not valid
assert.Error(t, SyncSpec{Image: "", Authentication: auth}.Validate(DeploymentModeSingle))
assert.Error(t, SyncSpec{Image: "", Authentication: auth}.Validate(DeploymentModeResilientSingle))
assert.Error(t, SyncSpec{Image: "", Authentication: auth}.Validate(DeploymentModeCluster))
assert.Error(t, SyncSpec{Image: "foo", Authentication: auth, Enabled: true}.Validate(DeploymentModeSingle))
assert.Error(t, SyncSpec{Image: "foo", Authentication: auth, Enabled: true}.Validate(DeploymentModeResilientSingle))
assert.Error(t, SyncSpec{Image: "foo", Authentication: auth, TLS: tls, Enabled: true}.Validate(DeploymentModeSingle))
assert.Error(t, SyncSpec{Image: "foo", Authentication: auth, TLS: tls, Enabled: true}.Validate(DeploymentModeResilientSingle))
}
func TestSyncSpecSetDefaults(t *testing.T) {
@ -58,8 +60,8 @@ func TestSyncSpecSetDefaults(t *testing.T) {
assert.Equal(t, "foo", def(SyncSpec{Image: "foo"}).Image)
assert.Equal(t, v1.PullAlways, def(SyncSpec{}).ImagePullPolicy)
assert.Equal(t, v1.PullNever, def(SyncSpec{ImagePullPolicy: v1.PullNever}).ImagePullPolicy)
assert.Equal(t, "test-jwt", def(SyncSpec{}).Authentication.JWTSecretName)
assert.Equal(t, "foo", def(SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: "foo"}}).Authentication.JWTSecretName)
assert.Equal(t, "test-jwt", def(SyncSpec{}).Authentication.GetJWTSecretName())
assert.Equal(t, "foo", def(SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: util.String("foo")}}).Authentication.GetJWTSecretName())
}
func TestSyncSpecResetImmutableFields(t *testing.T) {
@ -95,35 +97,35 @@ func TestSyncSpecResetImmutableFields(t *testing.T) {
nil,
},
{
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: "None"}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: "None"}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: "None"}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: util.String("None")}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: util.String("None")}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: util.String("None")}},
nil,
},
{
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: "foo"}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: "foo"}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: "foo"}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: util.String("foo")}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: util.String("foo")}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: util.String("foo")}},
nil,
},
{
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: "foo"}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: "foo2"}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: "foo2"}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: util.String("foo")}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: util.String("foo2")}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: util.String("foo2")}},
nil,
},
// Invalid changes
{
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: "foo"}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: "None"}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: "foo"}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: util.String("foo")}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: util.String("None")}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: util.String("foo")}},
[]string{"test.auth.jwtSecretName"},
},
{
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: "None"}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: "foo"}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: "None"}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: util.String("None")}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: util.String("foo")}},
SyncSpec{Authentication: AuthenticationSpec{JWTSecretName: util.String("None")}},
[]string{"test.auth.jwtSecretName"},
},
}

View file

@ -27,6 +27,7 @@ import (
"net"
"time"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
"github.com/arangodb/kube-arangodb/pkg/util/validation"
)
@ -37,9 +38,9 @@ const (
// TLSSpec holds TLS specific configuration settings
type TLSSpec struct {
CASecretName string `json:"caSecretName,omitempty"`
AltNames []string `json:"altNames,omitempty"`
TTL time.Duration `json:"ttl,omitempty"`
CASecretName *string `json:"caSecretName,omitempty"`
AltNames []string `json:"altNames,omitempty"`
TTL *time.Duration `json:"ttl,omitempty"`
}
const (
@ -47,14 +48,35 @@ const (
CASecretNameDisabled = "None"
)
// IsSecure returns true when a CA secret has been set, false otherwise.
func (s TLSSpec) IsSecure() bool {
return s.CASecretName != CASecretNameDisabled
// GetCASecretName returns the value of caSecretName.
func (s TLSSpec) GetCASecretName() string {
if s.CASecretName == nil {
return ""
}
return *s.CASecretName
}
// GetAltNames splits the list of AltNames into DNS names, IP addresses & email addresses.
// GetAltNames returns the value of altNames.
func (s TLSSpec) GetAltNames() []string {
return s.AltNames
}
// GetTTL returns the value of ttl.
func (s TLSSpec) GetTTL() time.Duration {
if s.TTL == nil {
return time.Duration(0)
}
return *s.TTL
}
// IsSecure returns true when a CA secret has been set, false otherwise.
func (s TLSSpec) IsSecure() bool {
return s.GetCASecretName() != CASecretNameDisabled
}
// GetParsedAltNames splits the list of AltNames into DNS names, IP addresses & email addresses.
// When an entry is not valid for any of those categories, an error is returned.
func (s TLSSpec) GetAltNames() (dnsNames, ipAddresses, emailAddresses []string, err error) {
func (s TLSSpec) GetParsedAltNames() (dnsNames, ipAddresses, emailAddresses []string, err error) {
for _, name := range s.AltNames {
if net.ParseIP(name) != nil {
ipAddresses = append(ipAddresses, name)
@ -72,10 +94,10 @@ func (s TLSSpec) GetAltNames() (dnsNames, ipAddresses, emailAddresses []string,
// Validate the given spec
func (s TLSSpec) Validate() error {
if s.IsSecure() {
if err := k8sutil.ValidateOptionalResourceName(s.CASecretName); err != nil {
if err := k8sutil.ValidateResourceName(s.GetCASecretName()); err != nil {
return maskAny(err)
}
if _, _, _, err := s.GetAltNames(); err != nil {
if _, _, _, err := s.GetParsedAltNames(); err != nil {
return maskAny(err)
}
}
@ -84,10 +106,27 @@ func (s TLSSpec) Validate() error {
// SetDefaults fills in missing defaults
func (s *TLSSpec) SetDefaults(defaultCASecretName string) {
if s.CASecretName == "" {
s.CASecretName = defaultCASecretName
if s.GetCASecretName() == "" {
// Note that we don't check for nil here, since even a specified, but empty
// string should result in the default value.
s.CASecretName = util.String(defaultCASecretName)
}
if s.TTL == 0 {
s.TTL = defaultTLSTTL
if s.GetTTL() == 0 {
// Note that we don't check for nil here, since even a specified, but zero
// should result in the default value.
s.TTL = util.Duration(defaultTLSTTL)
}
}
// SetDefaultsFrom fills unspecified fields with a value from given source spec.
func (s *TLSSpec) SetDefaultsFrom(source TLSSpec) {
if s.CASecretName == nil {
s.CASecretName = util.String(source.GetCASecretName())
}
if s.AltNames == nil {
s.AltNames = source.AltNames
}
if s.TTL == nil {
s.TTL = util.Duration(source.GetTTL())
}
}

View file

@ -26,27 +26,29 @@ import (
"testing"
"time"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/stretchr/testify/assert"
)
func TestTLSSpecValidate(t *testing.T) {
// Valid
assert.Nil(t, TLSSpec{CASecretName: ""}.Validate())
assert.Nil(t, TLSSpec{CASecretName: "foo"}.Validate())
assert.Nil(t, TLSSpec{CASecretName: "None"}.Validate())
assert.Nil(t, TLSSpec{AltNames: []string{}}.Validate())
assert.Nil(t, TLSSpec{AltNames: []string{"foo"}}.Validate())
assert.Nil(t, TLSSpec{AltNames: []string{"email@example.com", "127.0.0.1"}}.Validate())
assert.Nil(t, TLSSpec{CASecretName: util.String("foo")}.Validate())
assert.Nil(t, TLSSpec{CASecretName: util.String("None")}.Validate())
assert.Nil(t, TLSSpec{CASecretName: util.String("None"), AltNames: []string{}}.Validate())
assert.Nil(t, TLSSpec{CASecretName: util.String("None"), AltNames: []string{"foo"}}.Validate())
assert.Nil(t, TLSSpec{CASecretName: util.String("None"), AltNames: []string{"email@example.com", "127.0.0.1"}}.Validate())
// Not valid
assert.Error(t, TLSSpec{CASecretName: "Foo"}.Validate())
assert.Error(t, TLSSpec{AltNames: []string{"@@"}}.Validate())
assert.Error(t, TLSSpec{CASecretName: nil}.Validate())
assert.Error(t, TLSSpec{CASecretName: util.String("")}.Validate())
assert.Error(t, TLSSpec{CASecretName: util.String("Foo")}.Validate())
assert.Error(t, TLSSpec{CASecretName: util.String("foo"), AltNames: []string{"@@"}}.Validate())
}
func TestTLSSpecIsSecure(t *testing.T) {
assert.True(t, TLSSpec{CASecretName: ""}.IsSecure())
assert.True(t, TLSSpec{CASecretName: "foo"}.IsSecure())
assert.False(t, TLSSpec{CASecretName: "None"}.IsSecure())
assert.True(t, TLSSpec{CASecretName: util.String("")}.IsSecure())
assert.True(t, TLSSpec{CASecretName: util.String("foo")}.IsSecure())
assert.False(t, TLSSpec{CASecretName: util.String("None")}.IsSecure())
}
func TestTLSSpecSetDefaults(t *testing.T) {
@ -55,10 +57,10 @@ func TestTLSSpecSetDefaults(t *testing.T) {
return spec
}
assert.Equal(t, "", def(TLSSpec{}).CASecretName)
assert.Equal(t, "foo", def(TLSSpec{CASecretName: "foo"}).CASecretName)
assert.Equal(t, "", def(TLSSpec{}).GetCASecretName())
assert.Equal(t, "foo", def(TLSSpec{CASecretName: util.String("foo")}).GetCASecretName())
assert.Len(t, def(TLSSpec{}).AltNames, 0)
assert.Len(t, def(TLSSpec{AltNames: []string{"foo.local"}}).AltNames, 1)
assert.Equal(t, defaultTLSTTL, def(TLSSpec{}).TTL)
assert.Equal(t, time.Hour, def(TLSSpec{TTL: time.Hour}).TTL)
assert.Equal(t, defaultTLSTTL, def(TLSSpec{}).GetTTL())
assert.Equal(t, time.Hour, def(TLSSpec{TTL: util.Duration(time.Hour)}).GetTTL())
}

View file

@ -25,6 +25,8 @@
package v1alpha
import (
time "time"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
)
@ -198,6 +200,15 @@ func (in *DeploymentStatus) DeepCopyInto(out *DeploymentStatus) {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.AcceptedSpec != nil {
in, out := &in.AcceptedSpec, &out.AcceptedSpec
if *in == nil {
*out = nil
} else {
*out = new(DeploymentSpec)
(*in).DeepCopyInto(*out)
}
}
return
}
@ -401,11 +412,29 @@ func (in *SyncSpec) DeepCopy() *SyncSpec {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TLSSpec) DeepCopyInto(out *TLSSpec) {
*out = *in
if in.CASecretName != nil {
in, out := &in.CASecretName, &out.CASecretName
if *in == nil {
*out = nil
} else {
*out = new(string)
**out = **in
}
}
if in.AltNames != nil {
in, out := &in.AltNames, &out.AltNames
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.TTL != nil {
in, out := &in.TTL, &out.TTL
if *in == nil {
*out = nil
} else {
*out = new(time.Duration)
**out = **in
}
}
return
}

View file

@ -72,7 +72,7 @@ type deploymentEvent struct {
}
const (
deploymentEventQueueSize = 100
deploymentEventQueueSize = 256
minInspectionInterval = time.Second // Ensure we inspect the generated resources no less than with this interval
maxInspectionInterval = time.Minute // Ensure we inspect the generated resources no less than with this interval
)
@ -108,6 +108,10 @@ func New(config Config, deps Dependencies, apiObject *api.ArangoDeployment) (*De
eventsCli: deps.KubeCli.Core().Events(apiObject.GetNamespace()),
clientCache: newClientCache(deps.KubeCli, apiObject),
}
if d.status.AcceptedSpec == nil {
// We've validated the spec, so let's use it from now.
d.status.AcceptedSpec = apiObject.Spec.DeepCopy()
}
go d.run()
go d.listenForPodEvents()
@ -284,10 +288,14 @@ func (d *Deployment) handleArangoDeploymentUpdatedEvent(event *deploymentEvent)
return maskAny(err)
}
specBefore := d.apiObject.Spec
if d.status.AcceptedSpec != nil {
specBefore = *d.status.AcceptedSpec
}
newAPIObject := current.DeepCopy()
newAPIObject.Spec.SetDefaults(newAPIObject.GetName())
newAPIObject.Spec.SetDefaultsFrom(specBefore)
newAPIObject.Status = d.status
resetFields := d.apiObject.Spec.ResetImmutableFields(&newAPIObject.Spec)
resetFields := specBefore.ResetImmutableFields(&newAPIObject.Spec)
if len(resetFields) > 0 {
log.Debug().Strs("fields", resetFields).Msg("Found modified immutable fields")
}
@ -311,6 +319,11 @@ func (d *Deployment) handleArangoDeploymentUpdatedEvent(event *deploymentEvent)
if err := d.updateCRSpec(newAPIObject.Spec); err != nil {
return maskAny(fmt.Errorf("failed to update ArangoDeployment spec: %v", err))
}
// Save updated accepted spec
d.status.AcceptedSpec = newAPIObject.Spec.DeepCopy()
if err := d.updateCRStatus(); err != nil {
return maskAny(fmt.Errorf("failed to update ArangoDeployment status: %v", err))
}
// Trigger inspect
d.inspectTrigger.Trigger()

View file

@ -40,7 +40,7 @@ func (d *Deployment) createInitialMembers(apiObject *api.ArangoDeployment) error
// Go over all groups and create members
if err := apiObject.ForeachServerGroup(func(group api.ServerGroup, spec api.ServerGroupSpec, status *api.MemberStatusList) error {
for len(*status) < spec.Count {
for len(*status) < spec.GetCount() {
if err := d.createMember(group, apiObject); err != nil {
return maskAny(err)
}

View file

@ -69,13 +69,13 @@ func createPlan(log zerolog.Logger, currentPlan api.Plan, spec api.DeploymentSpe
// Never scale down
case api.DeploymentModeResilientSingle:
// Only scale singles
plan = append(plan, createScalePlan(log, status.Members.Single, api.ServerGroupSingle, spec.Single.Count)...)
plan = append(plan, createScalePlan(log, status.Members.Single, api.ServerGroupSingle, spec.Single.GetCount())...)
case api.DeploymentModeCluster:
// Scale dbservers, coordinators, syncmasters & syncworkers
plan = append(plan, createScalePlan(log, status.Members.DBServers, api.ServerGroupDBServers, spec.DBServers.Count)...)
plan = append(plan, createScalePlan(log, status.Members.Coordinators, api.ServerGroupCoordinators, spec.Coordinators.Count)...)
plan = append(plan, createScalePlan(log, status.Members.SyncMasters, api.ServerGroupSyncMasters, spec.SyncMasters.Count)...)
plan = append(plan, createScalePlan(log, status.Members.SyncWorkers, api.ServerGroupSyncWorkers, spec.SyncWorkers.Count)...)
plan = append(plan, createScalePlan(log, status.Members.DBServers, api.ServerGroupDBServers, spec.DBServers.GetCount())...)
plan = append(plan, createScalePlan(log, status.Members.Coordinators, api.ServerGroupCoordinators, spec.Coordinators.GetCount())...)
plan = append(plan, createScalePlan(log, status.Members.SyncMasters, api.ServerGroupSyncMasters, spec.SyncMasters.GetCount())...)
plan = append(plan, createScalePlan(log, status.Members.SyncWorkers, api.ServerGroupSyncWorkers, spec.SyncWorkers.GetCount())...)
}
// Return plan

View file

@ -139,7 +139,7 @@ func createArangodArgs(apiObject metav1.Object, deplSpec api.DeploymentSpec, gro
optionPair{"--cluster.my-id", id},
optionPair{"--agency.activate", "true"},
optionPair{"--agency.my-address", myTCPURL},
optionPair{"--agency.size", strconv.Itoa(deplSpec.Agents.Count)},
optionPair{"--agency.size", strconv.Itoa(deplSpec.Agents.GetCount())},
optionPair{"--agency.supervision", "true"},
optionPair{"--foxx.queues", "false"},
optionPair{"--server.statistics", "false"},
@ -242,7 +242,7 @@ func (d *Deployment) createLivenessProbe(apiObject *api.ArangoDeployment, group
return nil, nil
case api.ServerGroupSyncMasters, api.ServerGroupSyncWorkers:
authorization := ""
if apiObject.Spec.Sync.Monitoring.TokenSecretName != "" {
if apiObject.Spec.Sync.Monitoring.GetTokenSecretName() != "" {
// Use monitoring token
token, err := d.getSyncMonitoringToken(apiObject)
if err != nil {
@ -344,14 +344,14 @@ func (d *Deployment) ensurePods(apiObject *api.ArangoDeployment) error {
}
rocksdbEncryptionSecretName := ""
if apiObject.Spec.RocksDB.IsEncrypted() {
rocksdbEncryptionSecretName = apiObject.Spec.RocksDB.Encryption.KeySecretName
rocksdbEncryptionSecretName = apiObject.Spec.RocksDB.Encryption.GetKeySecretName()
if err := k8sutil.ValidateEncryptionKeySecret(kubecli.CoreV1(), rocksdbEncryptionSecretName, ns); err != nil {
return maskAny(errors.Wrapf(err, "RocksDB encryption key secret validation failed"))
}
}
if apiObject.Spec.IsAuthenticated() {
env[constants.EnvArangodJWTSecret] = k8sutil.EnvValue{
SecretName: apiObject.Spec.Authentication.JWTSecretName,
SecretName: apiObject.Spec.Authentication.GetJWTSecretName(),
SecretKey: constants.SecretKeyJWT,
}
}

View file

@ -38,7 +38,7 @@ func (d *Deployment) ensurePVCs(apiObject *api.ArangoDeployment) error {
if err := apiObject.ForeachServerGroup(func(group api.ServerGroup, spec api.ServerGroupSpec, status *api.MemberStatusList) error {
for _, m := range *status {
if m.PersistentVolumeClaimName != "" {
storageClassName := spec.StorageClassName
storageClassName := spec.GetStorageClassName()
role := group.AsRole()
resources := spec.Resources
if err := k8sutil.CreatePersistentVolumeClaim(kubecli, m.PersistentVolumeClaimName, deploymentName, ns, storageClassName, role, resources, owner); err != nil {

View file

@ -36,7 +36,7 @@ import (
// createSecrets creates all secrets needed to run the given deployment
func (d *Deployment) createSecrets(apiObject *api.ArangoDeployment) error {
if apiObject.Spec.IsAuthenticated() {
if err := d.ensureJWTSecret(apiObject.Spec.Authentication.JWTSecretName); err != nil {
if err := d.ensureJWTSecret(apiObject.Spec.Authentication.GetJWTSecretName()); err != nil {
return maskAny(err)
}
}
@ -88,7 +88,7 @@ func (d *Deployment) ensureJWTSecret(secretName string) error {
func (d *Deployment) ensureCACertificateSecret(spec api.TLSSpec) error {
kubecli := d.deps.KubeCli
ns := d.apiObject.GetNamespace()
if _, err := kubecli.CoreV1().Secrets(ns).Get(spec.CASecretName, metav1.GetOptions{}); k8sutil.IsNotFound(err) {
if _, err := kubecli.CoreV1().Secrets(ns).Get(spec.GetCASecretName(), metav1.GetOptions{}); k8sutil.IsNotFound(err) {
// Secret not found, create it
owner := d.apiObject.AsOwner()
deploymentName := d.apiObject.GetName()
@ -112,7 +112,7 @@ func (d *Deployment) getJWTSecret(apiObject *api.ArangoDeployment) (string, erro
return "", nil
}
kubecli := d.deps.KubeCli
secretName := apiObject.Spec.Authentication.JWTSecretName
secretName := apiObject.Spec.Authentication.GetJWTSecretName()
s, err := k8sutil.GetJWTSecret(kubecli.CoreV1(), secretName, apiObject.GetNamespace())
if err != nil {
d.deps.Log.Debug().Err(err).Str("secret-name", secretName).Msg("Failed to get JWT secret")
@ -124,7 +124,7 @@ func (d *Deployment) getJWTSecret(apiObject *api.ArangoDeployment) (string, erro
// getSyncJWTSecret loads the JWT secret used for syncmasters from a Secret configured in apiObject.Spec.Sync.Authentication.JWTSecretName.
func (d *Deployment) getSyncJWTSecret(apiObject *api.ArangoDeployment) (string, error) {
kubecli := d.deps.KubeCli
secretName := apiObject.Spec.Sync.Authentication.JWTSecretName
secretName := apiObject.Spec.Sync.Authentication.GetJWTSecretName()
s, err := k8sutil.GetJWTSecret(kubecli.CoreV1(), secretName, apiObject.GetNamespace())
if err != nil {
d.deps.Log.Debug().Err(err).Str("secret-name", secretName).Msg("Failed to get sync JWT secret")
@ -136,7 +136,7 @@ func (d *Deployment) getSyncJWTSecret(apiObject *api.ArangoDeployment) (string,
// getSyncMonitoringToken loads the token secret used for monitoring sync masters & workers.
func (d *Deployment) getSyncMonitoringToken(apiObject *api.ArangoDeployment) (string, error) {
kubecli := d.deps.KubeCli
secretName := apiObject.Spec.Sync.Monitoring.TokenSecretName
secretName := apiObject.Spec.Sync.Monitoring.GetTokenSecretName()
s, err := kubecli.CoreV1().Secrets(apiObject.GetNamespace()).Get(secretName, metav1.GetOptions{})
if err != nil {
d.deps.Log.Debug().Err(err).Str("secret-name", secretName).Msg("Failed to get monitoring token secret")

View file

@ -44,8 +44,8 @@ const (
// createCACertificate creates a CA certificate and stores it in a secret with name
// specified in the given spec.
func createCACertificate(log zerolog.Logger, cli v1.CoreV1Interface, spec api.TLSSpec, deploymentName, namespace string, ownerRef *metav1.OwnerReference) error {
log = log.With().Str("secret", spec.CASecretName).Logger()
dnsNames, ipAddresses, emailAddress, err := spec.GetAltNames()
log = log.With().Str("secret", spec.GetCASecretName()).Logger()
dnsNames, ipAddresses, emailAddress, err := spec.GetParsedAltNames()
if err != nil {
log.Debug().Err(err).Msg("Failed to get alternate names")
return maskAny(err)
@ -65,7 +65,7 @@ func createCACertificate(log zerolog.Logger, cli v1.CoreV1Interface, spec api.TL
log.Debug().Err(err).Msg("Failed to create CA certificate")
return maskAny(err)
}
if err := k8sutil.CreateCASecret(cli, spec.CASecretName, namespace, cert, priv, ownerRef); err != nil {
if err := k8sutil.CreateCASecret(cli, spec.GetCASecretName(), namespace, cert, priv, ownerRef); err != nil {
if k8sutil.IsAlreadyExists(err) {
log.Debug().Msg("CA Secret already exists")
} else {
@ -82,14 +82,14 @@ func createCACertificate(log zerolog.Logger, cli v1.CoreV1Interface, spec api.TL
func createServerCertificate(log zerolog.Logger, cli v1.CoreV1Interface, serverNames []string, spec api.TLSSpec, secretName, namespace string, ownerRef *metav1.OwnerReference) error {
log = log.With().Str("secret", secretName).Logger()
// Load alt names
dnsNames, ipAddresses, emailAddress, err := spec.GetAltNames()
dnsNames, ipAddresses, emailAddress, err := spec.GetParsedAltNames()
if err != nil {
log.Debug().Err(err).Msg("Failed to get alternate names")
return maskAny(err)
}
// Load CA certificate
caCert, caKey, err := k8sutil.GetCASecret(cli, spec.CASecretName, namespace)
caCert, caKey, err := k8sutil.GetCASecret(cli, spec.GetCASecretName(), namespace)
if err != nil {
log.Debug().Err(err).Msg("Failed to load CA certificate")
return maskAny(err)
@ -105,7 +105,7 @@ func createServerCertificate(log zerolog.Logger, cli v1.CoreV1Interface, serverN
Hosts: append(append(serverNames, dnsNames...), ipAddresses...),
EmailAddresses: emailAddress,
ValidFrom: time.Now(),
ValidFor: spec.TTL,
ValidFor: spec.GetTTL(),
IsCA: false,
ECDSACurve: tlsECDSACurve,
}

View file

@ -146,7 +146,7 @@ func createArangodClientForDNSName(ctx context.Context, cli corev1.CoreV1Interfa
// Authentication is enabled.
// Should we skip using it?
if ctx.Value(skipAuthenticationKey{}) == nil {
s, err := k8sutil.GetJWTSecret(cli, apiObject.Spec.Authentication.JWTSecretName, apiObject.GetNamespace())
s, err := k8sutil.GetJWTSecret(cli, apiObject.Spec.Authentication.GetJWTSecretName(), apiObject.GetNamespace())
if err != nil {
return nil, maskAny(err)
}

77
pkg/util/refs.go Normal file
View file

@ -0,0 +1,77 @@
//
// 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
//
// Author Ewout Prangsma
//
package util
import "time"
// String returns a reference to a string with given value.
func String(input string) *string {
return &input
}
// StringOrNil returns nil if input is nil, otherwise returns a clone of the given value.
func StringOrNil(input *string) *string {
if input == nil {
return nil
}
return String(*input)
}
// Int returns a reference to an int with given value.
func Int(input int) *int {
return &input
}
// IntOrNil returns nil if input is nil, otherwise returns a clone of the given value.
func IntOrNil(input *int) *int {
if input == nil {
return nil
}
return Int(*input)
}
// Bool returns a reference to a bool with given value.
func Bool(input bool) *bool {
return &input
}
// BoolOrNil returns nil if input is nil, otherwise returns a clone of the given value.
func BoolOrNil(input *bool) *bool {
if input == nil {
return nil
}
return Bool(*input)
}
// Duration returns a reference to a duration with given value.
func Duration(input time.Duration) *time.Duration {
return &input
}
// DurationOrNil returns nil if input is nil, otherwise returns a clone of the given value.
func DurationOrNil(input *time.Duration) *time.Duration {
if input == nil {
return nil
}
return Duration(*input)
}