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

[Feature] Add HostAliases for Sync (#1129)

This commit is contained in:
Adam Janikowski 2022-09-27 23:53:21 +02:00 committed by GitHub
parent 0bbdc15bf9
commit d7e7ad77c4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 961 additions and 3 deletions

View file

@ -7,6 +7,7 @@
- (Bugfix) Accept Initial Spec
- (Bugfix) Prevent LifeCycle restarts
- (Bugfix) Change SyncWorker Affinity to Soft
- (Feature) Add HostAliases for Sync
## [1.2.17](https://github.com/arangodb/kube-arangodb/tree/1.2.17) (2022-09-22)
- (Feature) Add new field to DeploymentReplicationStatus with details on DC2DC sync status=

View file

@ -374,6 +374,868 @@ func TestEnsurePod_Sync_Master(t *testing.T) {
},
},
},
{
DropInit: true,
Name: "Sync Master Pod alias - existing service, ClusterIP and valid name",
config: Config{
OperatorImage: testImageOperator,
},
ArangoDeployment: &api.ArangoDeployment{
Spec: api.DeploymentSpec{
Image: util.NewString(testImage),
Authentication: noAuthentication,
Environment: api.NewEnvironment(api.EnvironmentProduction),
Sync: api.SyncSpec{
Enabled: util.NewBool(true),
ExternalAccess: api.SyncExternalAccessSpec{
MasterEndpoint: []string{
"https://arangodb.xyz:8629",
},
},
},
License: api.LicenseSpec{
SecretName: util.NewString(testLicense),
},
},
},
Helper: func(t *testing.T, deployment *Deployment, testCase *testCaseStruct) {
deployment.currentObjectStatus = &api.DeploymentStatus{
Members: api.DeploymentStatusMembers{
SyncMasters: api.MemberStatusList{
firstSyncMaster,
},
},
Images: createTestImages(true),
}
svc := &core.Service{
ObjectMeta: meta.ObjectMeta{
Name: "test-sync",
},
Spec: core.ServiceSpec{
ClusterIP: "1.2.3.4",
},
}
deployment.GetCachedStatus().ServicesModInterface().V1().Create(context.Background(), svc, meta.CreateOptions{})
testCase.createTestPodData(deployment, api.ServerGroupSyncMasters, firstSyncMaster)
name := testCase.ArangoDeployment.Spec.Sync.Monitoring.GetTokenSecretName()
auth, err := k8sutil.GetTokenSecret(context.Background(), deployment.GetCachedStatus().Secret().V1().Read(), name)
require.NoError(t, err)
testCase.ExpectedPod.Spec.Containers[0].LivenessProbe = createTestLivenessProbe(
"", true, "bearer "+auth, shared.ArangoSyncMasterPort)
},
ExpectedEvent: "member syncmaster is created",
ExpectedPod: core.Pod{
Spec: core.PodSpec{
Volumes: []core.Volume{
k8sutil.LifecycleVolume(),
createTestTLSVolume(api.ServerGroupSyncMastersString, firstSyncMaster.ID),
k8sutil.CreateVolumeWithSecret(shared.ClientAuthCAVolumeName,
testDeploymentName+"-sync-client-auth-ca"),
k8sutil.CreateVolumeWithSecret(shared.MasterJWTSecretVolumeName,
testDeploymentName+"-sync-jwt"),
},
InitContainers: []core.Container{
createTestLifecycleContainer(emptyResources),
},
Containers: []core.Container{
{
Name: shared.ServerContainerName,
Image: testImage,
Command: createTestCommandForSyncMaster(firstSyncMaster.ID, true, false, true, "https://arangodb.xyz:8629"),
Ports: createTestPorts(),
Env: []core.EnvVar{
k8sutil.CreateEnvSecretKeySelector(constants.EnvArangoSyncMonitoringToken,
testDeploymentName+"-sync-mt", constants.SecretKeyToken),
k8sutil.CreateEnvSecretKeySelector(constants.EnvArangoLicenseKey,
testLicense, constants.SecretKeyToken),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorPodName, "metadata.name"),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorPodNamespace, "metadata.namespace"),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorNodeName, "spec.nodeName"),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorNodeNameArango, "spec.nodeName"),
},
Resources: emptyResources,
ImagePullPolicy: core.PullIfNotPresent,
Lifecycle: createTestLifecycle(api.ServerGroupSyncMasters),
SecurityContext: securityContext.NewSecurityContext(),
VolumeMounts: []core.VolumeMount{
k8sutil.LifecycleVolumeMount(),
k8sutil.TlsKeyfileVolumeMount(),
k8sutil.ClientAuthCACertificateVolumeMount(),
k8sutil.MasterJWTVolumeMount(),
},
},
},
RestartPolicy: core.RestartPolicyNever,
TerminationGracePeriodSeconds: &defaultSyncMasterTerminationTimeout,
Hostname: testDeploymentName + "-" + api.ServerGroupSyncMastersString + "-" +
firstSyncMaster.ID,
Subdomain: testDeploymentName + "-int",
Affinity: k8sutil.CreateAffinity(testDeploymentName, api.ServerGroupSyncMastersString,
true, ""),
HostAliases: []core.HostAlias{
{
IP: "1.2.3.4",
Hostnames: []string{
"arangodb.xyz",
},
},
},
},
},
},
{
DropInit: true,
Name: "Sync Master Pod alias - missing service and valid name",
config: Config{
OperatorImage: testImageOperator,
},
ArangoDeployment: &api.ArangoDeployment{
Spec: api.DeploymentSpec{
Image: util.NewString(testImage),
Authentication: noAuthentication,
Environment: api.NewEnvironment(api.EnvironmentProduction),
Sync: api.SyncSpec{
Enabled: util.NewBool(true),
ExternalAccess: api.SyncExternalAccessSpec{
MasterEndpoint: []string{
"https://arangodb.xyz:8629",
},
},
},
License: api.LicenseSpec{
SecretName: util.NewString(testLicense),
},
},
},
Helper: func(t *testing.T, deployment *Deployment, testCase *testCaseStruct) {
deployment.currentObjectStatus = &api.DeploymentStatus{
Members: api.DeploymentStatusMembers{
SyncMasters: api.MemberStatusList{
firstSyncMaster,
},
},
Images: createTestImages(true),
}
testCase.createTestPodData(deployment, api.ServerGroupSyncMasters, firstSyncMaster)
name := testCase.ArangoDeployment.Spec.Sync.Monitoring.GetTokenSecretName()
auth, err := k8sutil.GetTokenSecret(context.Background(), deployment.GetCachedStatus().Secret().V1().Read(), name)
require.NoError(t, err)
testCase.ExpectedPod.Spec.Containers[0].LivenessProbe = createTestLivenessProbe(
"", true, "bearer "+auth, shared.ArangoSyncMasterPort)
},
ExpectedEvent: "member syncmaster is created",
ExpectedPod: core.Pod{
Spec: core.PodSpec{
Volumes: []core.Volume{
k8sutil.LifecycleVolume(),
createTestTLSVolume(api.ServerGroupSyncMastersString, firstSyncMaster.ID),
k8sutil.CreateVolumeWithSecret(shared.ClientAuthCAVolumeName,
testDeploymentName+"-sync-client-auth-ca"),
k8sutil.CreateVolumeWithSecret(shared.MasterJWTSecretVolumeName,
testDeploymentName+"-sync-jwt"),
},
InitContainers: []core.Container{
createTestLifecycleContainer(emptyResources),
},
Containers: []core.Container{
{
Name: shared.ServerContainerName,
Image: testImage,
Command: createTestCommandForSyncMaster(firstSyncMaster.ID, true, false, true, "https://arangodb.xyz:8629"),
Ports: createTestPorts(),
Env: []core.EnvVar{
k8sutil.CreateEnvSecretKeySelector(constants.EnvArangoSyncMonitoringToken,
testDeploymentName+"-sync-mt", constants.SecretKeyToken),
k8sutil.CreateEnvSecretKeySelector(constants.EnvArangoLicenseKey,
testLicense, constants.SecretKeyToken),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorPodName, "metadata.name"),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorPodNamespace, "metadata.namespace"),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorNodeName, "spec.nodeName"),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorNodeNameArango, "spec.nodeName"),
},
Resources: emptyResources,
ImagePullPolicy: core.PullIfNotPresent,
Lifecycle: createTestLifecycle(api.ServerGroupSyncMasters),
SecurityContext: securityContext.NewSecurityContext(),
VolumeMounts: []core.VolumeMount{
k8sutil.LifecycleVolumeMount(),
k8sutil.TlsKeyfileVolumeMount(),
k8sutil.ClientAuthCACertificateVolumeMount(),
k8sutil.MasterJWTVolumeMount(),
},
},
},
RestartPolicy: core.RestartPolicyNever,
TerminationGracePeriodSeconds: &defaultSyncMasterTerminationTimeout,
Hostname: testDeploymentName + "-" + api.ServerGroupSyncMastersString + "-" +
firstSyncMaster.ID,
Subdomain: testDeploymentName + "-int",
Affinity: k8sutil.CreateAffinity(testDeploymentName, api.ServerGroupSyncMastersString,
true, ""),
},
},
},
{
DropInit: true,
Name: "Sync Master Pod alias - existing service, missing ClusterIP and valid name",
config: Config{
OperatorImage: testImageOperator,
},
ArangoDeployment: &api.ArangoDeployment{
Spec: api.DeploymentSpec{
Image: util.NewString(testImage),
Authentication: noAuthentication,
Environment: api.NewEnvironment(api.EnvironmentProduction),
Sync: api.SyncSpec{
Enabled: util.NewBool(true),
ExternalAccess: api.SyncExternalAccessSpec{
MasterEndpoint: []string{
"https://arangodb.xyz:8629",
},
},
},
License: api.LicenseSpec{
SecretName: util.NewString(testLicense),
},
},
},
Helper: func(t *testing.T, deployment *Deployment, testCase *testCaseStruct) {
deployment.currentObjectStatus = &api.DeploymentStatus{
Members: api.DeploymentStatusMembers{
SyncMasters: api.MemberStatusList{
firstSyncMaster,
},
},
Images: createTestImages(true),
}
svc := &core.Service{
ObjectMeta: meta.ObjectMeta{
Name: "test-sync",
},
}
deployment.GetCachedStatus().ServicesModInterface().V1().Create(context.Background(), svc, meta.CreateOptions{})
testCase.createTestPodData(deployment, api.ServerGroupSyncMasters, firstSyncMaster)
name := testCase.ArangoDeployment.Spec.Sync.Monitoring.GetTokenSecretName()
auth, err := k8sutil.GetTokenSecret(context.Background(), deployment.GetCachedStatus().Secret().V1().Read(), name)
require.NoError(t, err)
testCase.ExpectedPod.Spec.Containers[0].LivenessProbe = createTestLivenessProbe(
"", true, "bearer "+auth, shared.ArangoSyncMasterPort)
},
ExpectedEvent: "member syncmaster is created",
ExpectedPod: core.Pod{
Spec: core.PodSpec{
Volumes: []core.Volume{
k8sutil.LifecycleVolume(),
createTestTLSVolume(api.ServerGroupSyncMastersString, firstSyncMaster.ID),
k8sutil.CreateVolumeWithSecret(shared.ClientAuthCAVolumeName,
testDeploymentName+"-sync-client-auth-ca"),
k8sutil.CreateVolumeWithSecret(shared.MasterJWTSecretVolumeName,
testDeploymentName+"-sync-jwt"),
},
InitContainers: []core.Container{
createTestLifecycleContainer(emptyResources),
},
Containers: []core.Container{
{
Name: shared.ServerContainerName,
Image: testImage,
Command: createTestCommandForSyncMaster(firstSyncMaster.ID, true, false, true, "https://arangodb.xyz:8629"),
Ports: createTestPorts(),
Env: []core.EnvVar{
k8sutil.CreateEnvSecretKeySelector(constants.EnvArangoSyncMonitoringToken,
testDeploymentName+"-sync-mt", constants.SecretKeyToken),
k8sutil.CreateEnvSecretKeySelector(constants.EnvArangoLicenseKey,
testLicense, constants.SecretKeyToken),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorPodName, "metadata.name"),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorPodNamespace, "metadata.namespace"),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorNodeName, "spec.nodeName"),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorNodeNameArango, "spec.nodeName"),
},
Resources: emptyResources,
ImagePullPolicy: core.PullIfNotPresent,
Lifecycle: createTestLifecycle(api.ServerGroupSyncMasters),
SecurityContext: securityContext.NewSecurityContext(),
VolumeMounts: []core.VolumeMount{
k8sutil.LifecycleVolumeMount(),
k8sutil.TlsKeyfileVolumeMount(),
k8sutil.ClientAuthCACertificateVolumeMount(),
k8sutil.MasterJWTVolumeMount(),
},
},
},
RestartPolicy: core.RestartPolicyNever,
TerminationGracePeriodSeconds: &defaultSyncMasterTerminationTimeout,
Hostname: testDeploymentName + "-" + api.ServerGroupSyncMastersString + "-" +
firstSyncMaster.ID,
Subdomain: testDeploymentName + "-int",
Affinity: k8sutil.CreateAffinity(testDeploymentName, api.ServerGroupSyncMastersString,
true, ""),
},
},
},
{
DropInit: true,
Name: "Sync Master Pod alias - existing service, ClusterIP and invalid name",
config: Config{
OperatorImage: testImageOperator,
},
ArangoDeployment: &api.ArangoDeployment{
Spec: api.DeploymentSpec{
Image: util.NewString(testImage),
Authentication: noAuthentication,
Environment: api.NewEnvironment(api.EnvironmentProduction),
Sync: api.SyncSpec{
Enabled: util.NewBool(true),
ExternalAccess: api.SyncExternalAccessSpec{
MasterEndpoint: []string{
"https://127.0.0.1:8629",
},
},
},
License: api.LicenseSpec{
SecretName: util.NewString(testLicense),
},
},
},
Helper: func(t *testing.T, deployment *Deployment, testCase *testCaseStruct) {
deployment.currentObjectStatus = &api.DeploymentStatus{
Members: api.DeploymentStatusMembers{
SyncMasters: api.MemberStatusList{
firstSyncMaster,
},
},
Images: createTestImages(true),
}
svc := &core.Service{
ObjectMeta: meta.ObjectMeta{
Name: "test-sync",
},
Spec: core.ServiceSpec{
ClusterIP: "1.2.3.4",
},
}
deployment.GetCachedStatus().ServicesModInterface().V1().Create(context.Background(), svc, meta.CreateOptions{})
testCase.createTestPodData(deployment, api.ServerGroupSyncMasters, firstSyncMaster)
name := testCase.ArangoDeployment.Spec.Sync.Monitoring.GetTokenSecretName()
auth, err := k8sutil.GetTokenSecret(context.Background(), deployment.GetCachedStatus().Secret().V1().Read(), name)
require.NoError(t, err)
testCase.ExpectedPod.Spec.Containers[0].LivenessProbe = createTestLivenessProbe(
"", true, "bearer "+auth, shared.ArangoSyncMasterPort)
},
ExpectedEvent: "member syncmaster is created",
ExpectedPod: core.Pod{
Spec: core.PodSpec{
Volumes: []core.Volume{
k8sutil.LifecycleVolume(),
createTestTLSVolume(api.ServerGroupSyncMastersString, firstSyncMaster.ID),
k8sutil.CreateVolumeWithSecret(shared.ClientAuthCAVolumeName,
testDeploymentName+"-sync-client-auth-ca"),
k8sutil.CreateVolumeWithSecret(shared.MasterJWTSecretVolumeName,
testDeploymentName+"-sync-jwt"),
},
InitContainers: []core.Container{
createTestLifecycleContainer(emptyResources),
},
Containers: []core.Container{
{
Name: shared.ServerContainerName,
Image: testImage,
Command: createTestCommandForSyncMaster(firstSyncMaster.ID, true, false, true, "https://127.0.0.1:8629"),
Ports: createTestPorts(),
Env: []core.EnvVar{
k8sutil.CreateEnvSecretKeySelector(constants.EnvArangoSyncMonitoringToken,
testDeploymentName+"-sync-mt", constants.SecretKeyToken),
k8sutil.CreateEnvSecretKeySelector(constants.EnvArangoLicenseKey,
testLicense, constants.SecretKeyToken),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorPodName, "metadata.name"),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorPodNamespace, "metadata.namespace"),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorNodeName, "spec.nodeName"),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorNodeNameArango, "spec.nodeName"),
},
Resources: emptyResources,
ImagePullPolicy: core.PullIfNotPresent,
Lifecycle: createTestLifecycle(api.ServerGroupSyncMasters),
SecurityContext: securityContext.NewSecurityContext(),
VolumeMounts: []core.VolumeMount{
k8sutil.LifecycleVolumeMount(),
k8sutil.TlsKeyfileVolumeMount(),
k8sutil.ClientAuthCACertificateVolumeMount(),
k8sutil.MasterJWTVolumeMount(),
},
},
},
RestartPolicy: core.RestartPolicyNever,
TerminationGracePeriodSeconds: &defaultSyncMasterTerminationTimeout,
Hostname: testDeploymentName + "-" + api.ServerGroupSyncMastersString + "-" +
firstSyncMaster.ID,
Subdomain: testDeploymentName + "-int",
Affinity: k8sutil.CreateAffinity(testDeploymentName, api.ServerGroupSyncMastersString,
true, ""),
},
},
},
{
DropInit: true,
Name: "Sync Master Pod alias - existing service, ClusterIP and missing name",
config: Config{
OperatorImage: testImageOperator,
},
ArangoDeployment: &api.ArangoDeployment{
Spec: api.DeploymentSpec{
Image: util.NewString(testImage),
Authentication: noAuthentication,
Environment: api.NewEnvironment(api.EnvironmentProduction),
Sync: api.SyncSpec{
Enabled: util.NewBool(true),
},
License: api.LicenseSpec{
SecretName: util.NewString(testLicense),
},
},
},
Helper: func(t *testing.T, deployment *Deployment, testCase *testCaseStruct) {
deployment.currentObjectStatus = &api.DeploymentStatus{
Members: api.DeploymentStatusMembers{
SyncMasters: api.MemberStatusList{
firstSyncMaster,
},
},
Images: createTestImages(true),
}
svc := &core.Service{
ObjectMeta: meta.ObjectMeta{
Name: "test-sync",
},
Spec: core.ServiceSpec{
ClusterIP: "1.2.3.4",
},
}
deployment.GetCachedStatus().ServicesModInterface().V1().Create(context.Background(), svc, meta.CreateOptions{})
testCase.createTestPodData(deployment, api.ServerGroupSyncMasters, firstSyncMaster)
name := testCase.ArangoDeployment.Spec.Sync.Monitoring.GetTokenSecretName()
auth, err := k8sutil.GetTokenSecret(context.Background(), deployment.GetCachedStatus().Secret().V1().Read(), name)
require.NoError(t, err)
testCase.ExpectedPod.Spec.Containers[0].LivenessProbe = createTestLivenessProbe(
"", true, "bearer "+auth, shared.ArangoSyncMasterPort)
},
ExpectedEvent: "member syncmaster is created",
ExpectedPod: core.Pod{
Spec: core.PodSpec{
Volumes: []core.Volume{
k8sutil.LifecycleVolume(),
createTestTLSVolume(api.ServerGroupSyncMastersString, firstSyncMaster.ID),
k8sutil.CreateVolumeWithSecret(shared.ClientAuthCAVolumeName,
testDeploymentName+"-sync-client-auth-ca"),
k8sutil.CreateVolumeWithSecret(shared.MasterJWTSecretVolumeName,
testDeploymentName+"-sync-jwt"),
},
InitContainers: []core.Container{
createTestLifecycleContainer(emptyResources),
},
Containers: []core.Container{
{
Name: shared.ServerContainerName,
Image: testImage,
Command: createTestCommandForSyncMaster(firstSyncMaster.ID, true, false, true),
Ports: createTestPorts(),
Env: []core.EnvVar{
k8sutil.CreateEnvSecretKeySelector(constants.EnvArangoSyncMonitoringToken,
testDeploymentName+"-sync-mt", constants.SecretKeyToken),
k8sutil.CreateEnvSecretKeySelector(constants.EnvArangoLicenseKey,
testLicense, constants.SecretKeyToken),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorPodName, "metadata.name"),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorPodNamespace, "metadata.namespace"),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorNodeName, "spec.nodeName"),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorNodeNameArango, "spec.nodeName"),
},
Resources: emptyResources,
ImagePullPolicy: core.PullIfNotPresent,
Lifecycle: createTestLifecycle(api.ServerGroupSyncMasters),
SecurityContext: securityContext.NewSecurityContext(),
VolumeMounts: []core.VolumeMount{
k8sutil.LifecycleVolumeMount(),
k8sutil.TlsKeyfileVolumeMount(),
k8sutil.ClientAuthCACertificateVolumeMount(),
k8sutil.MasterJWTVolumeMount(),
},
},
},
RestartPolicy: core.RestartPolicyNever,
TerminationGracePeriodSeconds: &defaultSyncMasterTerminationTimeout,
Hostname: testDeploymentName + "-" + api.ServerGroupSyncMastersString + "-" +
firstSyncMaster.ID,
Subdomain: testDeploymentName + "-int",
Affinity: k8sutil.CreateAffinity(testDeploymentName, api.ServerGroupSyncMastersString,
true, ""),
},
},
},
{
DropInit: true,
Name: "Sync Master Pod alias - existing service, ClusterIP and valid names",
config: Config{
OperatorImage: testImageOperator,
},
ArangoDeployment: &api.ArangoDeployment{
Spec: api.DeploymentSpec{
Image: util.NewString(testImage),
Authentication: noAuthentication,
Environment: api.NewEnvironment(api.EnvironmentProduction),
Sync: api.SyncSpec{
Enabled: util.NewBool(true),
ExternalAccess: api.SyncExternalAccessSpec{
MasterEndpoint: []string{
"https://arangodb.xyz:8629",
"https://arangodb1.xyz:8629",
"https://arangodb2.xyz:8629",
},
},
},
License: api.LicenseSpec{
SecretName: util.NewString(testLicense),
},
},
},
Helper: func(t *testing.T, deployment *Deployment, testCase *testCaseStruct) {
deployment.currentObjectStatus = &api.DeploymentStatus{
Members: api.DeploymentStatusMembers{
SyncMasters: api.MemberStatusList{
firstSyncMaster,
},
},
Images: createTestImages(true),
}
svc := &core.Service{
ObjectMeta: meta.ObjectMeta{
Name: "test-sync",
},
Spec: core.ServiceSpec{
ClusterIP: "1.2.3.4",
},
}
deployment.GetCachedStatus().ServicesModInterface().V1().Create(context.Background(), svc, meta.CreateOptions{})
testCase.createTestPodData(deployment, api.ServerGroupSyncMasters, firstSyncMaster)
name := testCase.ArangoDeployment.Spec.Sync.Monitoring.GetTokenSecretName()
auth, err := k8sutil.GetTokenSecret(context.Background(), deployment.GetCachedStatus().Secret().V1().Read(), name)
require.NoError(t, err)
testCase.ExpectedPod.Spec.Containers[0].LivenessProbe = createTestLivenessProbe(
"", true, "bearer "+auth, shared.ArangoSyncMasterPort)
},
ExpectedEvent: "member syncmaster is created",
ExpectedPod: core.Pod{
Spec: core.PodSpec{
Volumes: []core.Volume{
k8sutil.LifecycleVolume(),
createTestTLSVolume(api.ServerGroupSyncMastersString, firstSyncMaster.ID),
k8sutil.CreateVolumeWithSecret(shared.ClientAuthCAVolumeName,
testDeploymentName+"-sync-client-auth-ca"),
k8sutil.CreateVolumeWithSecret(shared.MasterJWTSecretVolumeName,
testDeploymentName+"-sync-jwt"),
},
InitContainers: []core.Container{
createTestLifecycleContainer(emptyResources),
},
Containers: []core.Container{
{
Name: shared.ServerContainerName,
Image: testImage,
Command: createTestCommandForSyncMaster(firstSyncMaster.ID, true, false, true, "https://arangodb.xyz:8629", "https://arangodb1.xyz:8629", "https://arangodb2.xyz:8629"),
Ports: createTestPorts(),
Env: []core.EnvVar{
k8sutil.CreateEnvSecretKeySelector(constants.EnvArangoSyncMonitoringToken,
testDeploymentName+"-sync-mt", constants.SecretKeyToken),
k8sutil.CreateEnvSecretKeySelector(constants.EnvArangoLicenseKey,
testLicense, constants.SecretKeyToken),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorPodName, "metadata.name"),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorPodNamespace, "metadata.namespace"),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorNodeName, "spec.nodeName"),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorNodeNameArango, "spec.nodeName"),
},
Resources: emptyResources,
ImagePullPolicy: core.PullIfNotPresent,
Lifecycle: createTestLifecycle(api.ServerGroupSyncMasters),
SecurityContext: securityContext.NewSecurityContext(),
VolumeMounts: []core.VolumeMount{
k8sutil.LifecycleVolumeMount(),
k8sutil.TlsKeyfileVolumeMount(),
k8sutil.ClientAuthCACertificateVolumeMount(),
k8sutil.MasterJWTVolumeMount(),
},
},
},
RestartPolicy: core.RestartPolicyNever,
TerminationGracePeriodSeconds: &defaultSyncMasterTerminationTimeout,
Hostname: testDeploymentName + "-" + api.ServerGroupSyncMastersString + "-" +
firstSyncMaster.ID,
Subdomain: testDeploymentName + "-int",
Affinity: k8sutil.CreateAffinity(testDeploymentName, api.ServerGroupSyncMastersString,
true, ""),
HostAliases: []core.HostAlias{
{
IP: "1.2.3.4",
Hostnames: []string{
"arangodb.xyz",
"arangodb1.xyz",
"arangodb2.xyz",
},
},
},
},
},
},
{
DropInit: true,
Name: "Sync Master Pod alias - existing service, ClusterIP and valid names with different ports",
config: Config{
OperatorImage: testImageOperator,
},
ArangoDeployment: &api.ArangoDeployment{
Spec: api.DeploymentSpec{
Image: util.NewString(testImage),
Authentication: noAuthentication,
Environment: api.NewEnvironment(api.EnvironmentProduction),
Sync: api.SyncSpec{
Enabled: util.NewBool(true),
ExternalAccess: api.SyncExternalAccessSpec{
MasterEndpoint: []string{
"https://arangodb.xyz:8629",
"https://arangodb.xyz:8639",
"https://arangodb.xyz:8649",
},
},
},
License: api.LicenseSpec{
SecretName: util.NewString(testLicense),
},
},
},
Helper: func(t *testing.T, deployment *Deployment, testCase *testCaseStruct) {
deployment.currentObjectStatus = &api.DeploymentStatus{
Members: api.DeploymentStatusMembers{
SyncMasters: api.MemberStatusList{
firstSyncMaster,
},
},
Images: createTestImages(true),
}
svc := &core.Service{
ObjectMeta: meta.ObjectMeta{
Name: "test-sync",
},
Spec: core.ServiceSpec{
ClusterIP: "1.2.3.4",
},
}
deployment.GetCachedStatus().ServicesModInterface().V1().Create(context.Background(), svc, meta.CreateOptions{})
testCase.createTestPodData(deployment, api.ServerGroupSyncMasters, firstSyncMaster)
name := testCase.ArangoDeployment.Spec.Sync.Monitoring.GetTokenSecretName()
auth, err := k8sutil.GetTokenSecret(context.Background(), deployment.GetCachedStatus().Secret().V1().Read(), name)
require.NoError(t, err)
testCase.ExpectedPod.Spec.Containers[0].LivenessProbe = createTestLivenessProbe(
"", true, "bearer "+auth, shared.ArangoSyncMasterPort)
},
ExpectedEvent: "member syncmaster is created",
ExpectedPod: core.Pod{
Spec: core.PodSpec{
Volumes: []core.Volume{
k8sutil.LifecycleVolume(),
createTestTLSVolume(api.ServerGroupSyncMastersString, firstSyncMaster.ID),
k8sutil.CreateVolumeWithSecret(shared.ClientAuthCAVolumeName,
testDeploymentName+"-sync-client-auth-ca"),
k8sutil.CreateVolumeWithSecret(shared.MasterJWTSecretVolumeName,
testDeploymentName+"-sync-jwt"),
},
InitContainers: []core.Container{
createTestLifecycleContainer(emptyResources),
},
Containers: []core.Container{
{
Name: shared.ServerContainerName,
Image: testImage,
Command: createTestCommandForSyncMaster(firstSyncMaster.ID, true, false, true, "https://arangodb.xyz:8629", "https://arangodb.xyz:8639", "https://arangodb.xyz:8649"),
Ports: createTestPorts(),
Env: []core.EnvVar{
k8sutil.CreateEnvSecretKeySelector(constants.EnvArangoSyncMonitoringToken,
testDeploymentName+"-sync-mt", constants.SecretKeyToken),
k8sutil.CreateEnvSecretKeySelector(constants.EnvArangoLicenseKey,
testLicense, constants.SecretKeyToken),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorPodName, "metadata.name"),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorPodNamespace, "metadata.namespace"),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorNodeName, "spec.nodeName"),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorNodeNameArango, "spec.nodeName"),
},
Resources: emptyResources,
ImagePullPolicy: core.PullIfNotPresent,
Lifecycle: createTestLifecycle(api.ServerGroupSyncMasters),
SecurityContext: securityContext.NewSecurityContext(),
VolumeMounts: []core.VolumeMount{
k8sutil.LifecycleVolumeMount(),
k8sutil.TlsKeyfileVolumeMount(),
k8sutil.ClientAuthCACertificateVolumeMount(),
k8sutil.MasterJWTVolumeMount(),
},
},
},
RestartPolicy: core.RestartPolicyNever,
TerminationGracePeriodSeconds: &defaultSyncMasterTerminationTimeout,
Hostname: testDeploymentName + "-" + api.ServerGroupSyncMastersString + "-" +
firstSyncMaster.ID,
Subdomain: testDeploymentName + "-int",
Affinity: k8sutil.CreateAffinity(testDeploymentName, api.ServerGroupSyncMastersString,
true, ""),
HostAliases: []core.HostAlias{
{
IP: "1.2.3.4",
Hostnames: []string{
"arangodb.xyz",
},
},
},
},
},
},
{
DropInit: true,
Name: "Sync Master Pod alias - existing service, ClusterIP and mixed names",
config: Config{
OperatorImage: testImageOperator,
},
ArangoDeployment: &api.ArangoDeployment{
Spec: api.DeploymentSpec{
Image: util.NewString(testImage),
Authentication: noAuthentication,
Environment: api.NewEnvironment(api.EnvironmentProduction),
Sync: api.SyncSpec{
Enabled: util.NewBool(true),
ExternalAccess: api.SyncExternalAccessSpec{
MasterEndpoint: []string{
"https://arangodb2.xyz:8629",
"https://arangodb.xyz:8629",
"https://127.0.0.1:8629",
},
},
},
License: api.LicenseSpec{
SecretName: util.NewString(testLicense),
},
},
},
Helper: func(t *testing.T, deployment *Deployment, testCase *testCaseStruct) {
deployment.currentObjectStatus = &api.DeploymentStatus{
Members: api.DeploymentStatusMembers{
SyncMasters: api.MemberStatusList{
firstSyncMaster,
},
},
Images: createTestImages(true),
}
svc := &core.Service{
ObjectMeta: meta.ObjectMeta{
Name: "test-sync",
},
Spec: core.ServiceSpec{
ClusterIP: "1.2.3.4",
},
}
deployment.GetCachedStatus().ServicesModInterface().V1().Create(context.Background(), svc, meta.CreateOptions{})
testCase.createTestPodData(deployment, api.ServerGroupSyncMasters, firstSyncMaster)
name := testCase.ArangoDeployment.Spec.Sync.Monitoring.GetTokenSecretName()
auth, err := k8sutil.GetTokenSecret(context.Background(), deployment.GetCachedStatus().Secret().V1().Read(), name)
require.NoError(t, err)
testCase.ExpectedPod.Spec.Containers[0].LivenessProbe = createTestLivenessProbe(
"", true, "bearer "+auth, shared.ArangoSyncMasterPort)
},
ExpectedEvent: "member syncmaster is created",
ExpectedPod: core.Pod{
Spec: core.PodSpec{
Volumes: []core.Volume{
k8sutil.LifecycleVolume(),
createTestTLSVolume(api.ServerGroupSyncMastersString, firstSyncMaster.ID),
k8sutil.CreateVolumeWithSecret(shared.ClientAuthCAVolumeName,
testDeploymentName+"-sync-client-auth-ca"),
k8sutil.CreateVolumeWithSecret(shared.MasterJWTSecretVolumeName,
testDeploymentName+"-sync-jwt"),
},
InitContainers: []core.Container{
createTestLifecycleContainer(emptyResources),
},
Containers: []core.Container{
{
Name: shared.ServerContainerName,
Image: testImage,
Command: createTestCommandForSyncMaster(firstSyncMaster.ID, true, false, true, "https://127.0.0.1:8629", "https://arangodb.xyz:8629", "https://arangodb2.xyz:8629"),
Ports: createTestPorts(),
Env: []core.EnvVar{
k8sutil.CreateEnvSecretKeySelector(constants.EnvArangoSyncMonitoringToken,
testDeploymentName+"-sync-mt", constants.SecretKeyToken),
k8sutil.CreateEnvSecretKeySelector(constants.EnvArangoLicenseKey,
testLicense, constants.SecretKeyToken),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorPodName, "metadata.name"),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorPodNamespace, "metadata.namespace"),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorNodeName, "spec.nodeName"),
k8sutil.CreateEnvFieldPath(constants.EnvOperatorNodeNameArango, "spec.nodeName"),
},
Resources: emptyResources,
ImagePullPolicy: core.PullIfNotPresent,
Lifecycle: createTestLifecycle(api.ServerGroupSyncMasters),
SecurityContext: securityContext.NewSecurityContext(),
VolumeMounts: []core.VolumeMount{
k8sutil.LifecycleVolumeMount(),
k8sutil.TlsKeyfileVolumeMount(),
k8sutil.ClientAuthCACertificateVolumeMount(),
k8sutil.MasterJWTVolumeMount(),
},
},
},
RestartPolicy: core.RestartPolicyNever,
TerminationGracePeriodSeconds: &defaultSyncMasterTerminationTimeout,
Hostname: testDeploymentName + "-" + api.ServerGroupSyncMastersString + "-" +
firstSyncMaster.ID,
Subdomain: testDeploymentName + "-int",
Affinity: k8sutil.CreateAffinity(testDeploymentName, api.ServerGroupSyncMastersString,
true, ""),
HostAliases: []core.HostAlias{
{
IP: "1.2.3.4",
Hostnames: []string{
"arangodb.xyz",
"arangodb2.xyz",
},
},
},
},
},
},
}
runTestCases(t, testCases...)

View file

@ -415,7 +415,8 @@ func createTestCommandForAgent(name string, tls, auth, encryptionRocksDB bool) [
return command
}
func createTestCommandForSyncMaster(name string, tls, auth, monitoring bool) []string {
//nolint:unparam
func createTestCommandForSyncMaster(name string, tls, auth, monitoring bool, customEndpoints ...string) []string {
command := []string{resources.ArangoSyncExecutor, "run", "master"}
if tls {
@ -428,7 +429,15 @@ func createTestCommandForSyncMaster(name string, tls, auth, monitoring bool) []s
command = append(command, "--cluster.jwt-secret=/secrets/cluster/jwt/token")
}
command = append(command, "--master.endpoint=https://"+testDeploymentName+"-sync.default.svc:8629")
if len(customEndpoints) == 0 {
customEndpoints = []string{
"https://" + testDeploymentName + "-sync.default.svc:8629",
}
}
for _, customEndpoint := range customEndpoints {
command = append(command, "--master.endpoint="+customEndpoint)
}
command = append(command, "--master.jwt-secret=/secrets/master/jwt/token")

View file

@ -372,6 +372,7 @@ func (r *Resources) RenderPodForMember(ctx context.Context, acs sutil.ACS, spec
arangoMember: *member,
apiObject: apiObject,
memberStatus: m,
cachedStatus: cache,
}
} else {
return nil, errors.Newf("unable to render Pod")

View file

@ -23,6 +23,8 @@ package resources
import (
"context"
"math"
"net"
"net/url"
core "k8s.io/api/core/v1"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -31,6 +33,7 @@ import (
"github.com/arangodb/kube-arangodb/pkg/apis/shared"
"github.com/arangodb/kube-arangodb/pkg/deployment/features"
"github.com/arangodb/kube-arangodb/pkg/deployment/pod"
"github.com/arangodb/kube-arangodb/pkg/handlers/utils"
"github.com/arangodb/kube-arangodb/pkg/util/collection"
"github.com/arangodb/kube-arangodb/pkg/util/constants"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
@ -74,6 +77,7 @@ type MemberSyncPod struct {
imageInfo api.ImageInfo
apiObject meta.Object
memberStatus api.MemberStatus
cachedStatus interfaces.Inspector
}
func (a *ArangoSyncContainer) GetArgs() ([]string, error) {
@ -321,6 +325,10 @@ func (m *MemberSyncPod) Init(ctx context.Context, cachedStatus interfaces.Inspec
pod.Spec.TerminationGracePeriodSeconds = &terminationGracePeriodSeconds
pod.Spec.PriorityClassName = m.groupSpec.PriorityClassName
if alias := m.syncHostAlias(); alias != nil {
pod.Spec.HostAliases = append(pod.Spec.HostAliases, *alias)
}
m.masterJWTSecretName = m.spec.Sync.Authentication.GetJWTSecretName()
err := globals.GetGlobalTimeouts().Kubernetes().RunWithTimeout(ctx, func(ctxChild context.Context) error {
return k8sutil.ValidateTokenSecret(ctxChild, cachedStatus.Secret().V1().Read(), m.masterJWTSecretName)
@ -420,3 +428,60 @@ func createArangoSyncVolumes(tlsKeyfileSecretName, clientAuthCASecretName, maste
return volumes
}
func (m *MemberSyncPod) syncHostAlias() *core.HostAlias {
svcName := k8sutil.CreateSyncMasterClientServiceName(m.apiObject.GetName())
svc, ok := m.cachedStatus.Service().V1().GetSimple(svcName)
if !ok {
return nil
}
endpoint := k8sutil.CreateSyncMasterClientServiceDNSNameWithDomain(m.apiObject, m.spec.ClusterDomain)
if svc.Spec.ClusterIP == "" {
return nil
}
var alias core.HostAlias
alias.IP = svc.Spec.ClusterIP
var aliases utils.StringList
for _, u := range m.spec.Sync.ExternalAccess.ResolveMasterEndpoint(svcName, shared.ArangoSyncMasterPort) {
url, err := url.Parse(u)
if err != nil {
continue
}
host := url.Host
if h, _, err := net.SplitHostPort(host); err == nil {
host = h
}
if host == endpoint {
continue
}
if host == svcName {
continue
}
if ip := net.ParseIP(host); ip != nil {
continue
}
aliases = append(aliases, host)
}
if len(aliases) == 0 {
return nil
}
aliases = aliases.Sort().Unique()
alias.Hostnames = aliases
return &alias
}

View file

@ -20,7 +20,10 @@
package utils
import "math/rand"
import (
"math/rand"
"sort"
)
var (
randomBase = []rune("abcdefghijklmnopqrstuvwxyz0123456789")
@ -61,6 +64,23 @@ func (s StringList) Remove(i ...string) StringList {
return r
}
func (s StringList) Sort() StringList {
sort.Slice(s, func(i, j int) bool {
return s[i] < s[j]
})
return s
}
func (s StringList) Unique() StringList {
z := make(StringList, 0, len(s))
for _, t := range s {
if !z.Has(t) {
z = append(z, t)
}
}
return z
}
// RandomString generates random string
func RandomString(n int) string {
return RandomStringFrom(n, randomBase)