Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LOG-5021: add validation if no secret for Cloudwatch and Splunk output #2331

Merged
merged 2 commits into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -316,9 +316,14 @@ func verifyOutputSecret(namespace string, clfClient client.Client, output *loggi
conds.Set(output.Name, c)
return false
}

if output.Secret == nil {
if output.Type == loggingv1.OutputTypeCloudwatch || output.Type == loggingv1.OutputTypeSplunk {
return fail(conditions.CondMissing("secret must be provided for %s output", output.Type))
}
return true
}

if output.Secret.Name == "" {
conds.Set(output.Name, conditions.CondInvalid("secret has empty name"))
return false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,16 @@ var _ = Describe("Validate clusterlogforwarderspec", func() {
})

Context("output specs", func() {
const secretName = "mytestsecret"
var (
client client.Client
namespace = constants.OpenshiftNS
extras map[string]bool
clfStatus *loggingv1.ClusterLogForwarderStatus
output loggingv1.OutputSpec
otherOutput loggingv1.OutputSpec
forwarderSpec *loggingv1.ClusterLogForwarderSpec
client client.Client
namespace = constants.OpenshiftNS
extras map[string]bool
clfStatus *loggingv1.ClusterLogForwarderStatus
output loggingv1.OutputSpec
otherOutput loggingv1.OutputSpec
forwarderSpec *loggingv1.ClusterLogForwarderSpec
cloudWatchSecret *corev1.Secret
)

BeforeEach(func() {
Expand All @@ -55,6 +57,11 @@ var _ = Describe("Validate clusterlogforwarderspec", func() {
clfStatus = &loggingv1.ClusterLogForwarderStatus{}
extras = map[string]bool{}

cloudWatchSecret = runtime.NewSecret(constants.OpenshiftNS, secretName, map[string][]byte{
constants.AWSSecretAccessKey: {0, 1, 2},
constants.AWSAccessKeyID: {0, 1, 2},
})

output = loggingv1.OutputSpec{
Name: "myOutput",
Type: "elasticsearch",
Expand Down Expand Up @@ -220,17 +227,22 @@ var _ = Describe("Validate clusterlogforwarderspec", func() {
})

It("should fail Cloudwatch output without OutputTypeSpec", func() {
client = fake.NewFakeClient(cloudWatchSecret) //nolint
forwarderSpec.Outputs = []loggingv1.OutputSpec{
{
Name: "cw",
Type: loggingv1.OutputTypeCloudwatch,
Secret: &loggingv1.OutputSecretSpec{
Name: secretName,
},
},
}
verifyOutputs(namespace, client, forwarderSpec, clfStatus, extras)
Expect(clfStatus.Outputs["cw"]).To(HaveCondition("Ready", false, "Invalid", "Cloudwatch output requires type spec"))
})

It("should allow specific outputs that do not require URL", func() {
client = fake.NewFakeClient(cloudWatchSecret) //nolint
forwarderSpec.Pipelines = []loggingv1.PipelineSpec{{OutputRefs: []string{"aCloudwatch"}}}
forwarderSpec.Outputs = []loggingv1.OutputSpec{
{
Expand All @@ -239,6 +251,9 @@ var _ = Describe("Validate clusterlogforwarderspec", func() {
OutputTypeSpec: loggingv1.OutputTypeSpec{
Cloudwatch: &loggingv1.Cloudwatch{},
},
Secret: &loggingv1.OutputSecretSpec{
Name: secretName,
},
},
}
verifyOutputs(namespace, client, forwarderSpec, clfStatus, extras)
Expand Down Expand Up @@ -304,7 +319,7 @@ var _ = Describe("Validate clusterlogforwarderspec", func() {
APIVersion: corev1.SchemeGroupVersion.String(),
},
ObjectMeta: metav1.ObjectMeta{
Name: "mytestsecret",
Name: secretName,
Namespace: constants.OpenshiftNS,
},
Data: map[string][]byte{},
Expand Down Expand Up @@ -332,7 +347,23 @@ var _ = Describe("Validate clusterlogforwarderspec", func() {
Expect(clfStatus.Outputs["aName"]).To(HaveCondition("Ready", false, "MissingResource", missingMessage))
})

It("should fail outputs with secrets that is missing aws_secret_access_id", func() {
It("should fail outputs without secrets", func() {
client = fake.NewFakeClient(secret) //nolint
output = loggingv1.OutputSpec{
Name: "aName",
Type: loggingv1.OutputTypeCloudwatch,
OutputTypeSpec: loggingv1.OutputTypeSpec{
Cloudwatch: &loggingv1.Cloudwatch{},
},
}
forwarderSpec = &loggingv1.ClusterLogForwarderSpec{}
forwarderSpec.Pipelines = []loggingv1.PipelineSpec{{OutputRefs: []string{output.Name}}}
forwarderSpec.Outputs = []loggingv1.OutputSpec{output}
verifyOutputs(namespace, client, forwarderSpec, clfStatus, extras)
Expect(clfStatus.Outputs["aName"]).To(HaveCondition("Ready", false, "MissingResource", "secret must be provided for cloudwatch output"))
})

It("should fail outputs without secrets that is missing aws_secret_access_id", func() {
secret.Data[constants.AWSSecretAccessKey] = []byte{0, 1, 2}
client = fake.NewFakeClient(secret) //nolint
verifyOutputs(namespace, client, forwarderSpec, clfStatus, extras)
Expand Down Expand Up @@ -397,6 +428,68 @@ var _ = Describe("Validate clusterlogforwarderspec", func() {
})
})

Context("for writing to Splunk", func() {
BeforeEach(func() {
output = loggingv1.OutputSpec{
Name: "aName",
Type: loggingv1.OutputTypeSplunk,
URL: "https://splunk-web:8088/endpoint",
OutputTypeSpec: loggingv1.OutputTypeSpec{
Splunk: &loggingv1.Splunk{},
},
Secret: &loggingv1.OutputSecretSpec{Name: secret.Name},
}
forwarderSpec.Pipelines = []loggingv1.PipelineSpec{{OutputRefs: []string{output.Name}}}
forwarderSpec.Outputs = []loggingv1.OutputSpec{output}
})

It("should fail outputs with secrets that is missing hecToken", func() {
client = fake.NewFakeClient(secret) //nolint
verifyOutputs(namespace, client, forwarderSpec, clfStatus, extras)
Expect(clfStatus.Outputs["aName"]).To(HaveCondition("Ready", false, "MissingResource", "A non-empty hecToken entry is required"))
})

It("should fail outputs without secrets", func() {
client = fake.NewFakeClient(secret) //nolint
output = loggingv1.OutputSpec{
Name: "aName",
URL: "https://splunk-web:8088/endpoint",
Type: loggingv1.OutputTypeSplunk,
OutputTypeSpec: loggingv1.OutputTypeSpec{
Splunk: &loggingv1.Splunk{},
},
}
forwarderSpec = &loggingv1.ClusterLogForwarderSpec{}
forwarderSpec.Pipelines = []loggingv1.PipelineSpec{{OutputRefs: []string{output.Name}}}
forwarderSpec.Outputs = []loggingv1.OutputSpec{output}
verifyOutputs(namespace, client, forwarderSpec, clfStatus, extras)
Expect(clfStatus.Outputs["aName"]).To(HaveCondition("Ready", false, "MissingResource", "secret must be provided for splunk output"))
})

It("should fail outputs with secrets that have empty hecToken", func() {
secret.Data[constants.SplunkHECTokenKey] = []byte{}
client = fake.NewFakeClient(secret) //nolint
verifyOutputs(namespace, client, forwarderSpec, clfStatus, extras)
Expect(clfStatus.Outputs["aName"]).To(HaveCondition("Ready", false, "MissingResource", "A non-empty hecToken entry is required"))
})

It("should pass outputs with secrets that have hecToken", func() {
secret.Data[constants.SplunkHECTokenKey] = []byte{0, 1, 2}
client = fake.NewFakeClient(secret) //nolint
verifyOutputs(namespace, client, forwarderSpec, clfStatus, extras)
Expect(forwarderSpec.Outputs).To(HaveLen(len(forwarderSpec.Outputs)))
Expect(clfStatus.Outputs["aName"]).To(HaveCondition("Ready", true, "", ""))
})

It("should fail outputs without URL", func() {
forwarderSpec.Outputs[0].URL = ""
secret.Data[constants.SplunkHECTokenKey] = []byte{0, 1, 2}
client = fake.NewFakeClient(secret) //nolint
verifyOutputs(namespace, client, forwarderSpec, clfStatus, extras)
Expect(clfStatus.Outputs["aName"]).To(HaveCondition("Ready", false, "Invalid", "URL is required for output type splunk"))
})
})

Context("with certs", func() {
BeforeEach(func() {
output = loggingv1.OutputSpec{
Expand Down Expand Up @@ -486,9 +579,15 @@ var _ = Describe("Validate clusterlogforwarderspec", func() {
var (
forwarderSpec = loggingv1.ClusterLogForwarderSpec{}
splunkOutputName = "splunk-index"
splunkSecret *corev1.Secret
)

BeforeEach(func() {
splunkSecret = runtime.NewSecret(constants.OpenshiftNS, "mysecret", map[string][]byte{
constants.SplunkHECTokenKey: {'t', 'o', 'k', 'e', 'n'},
})
forwarderSpec.Pipelines = []loggingv1.PipelineSpec{{OutputRefs: []string{splunkOutputName}}}
client = fake.NewFakeClient(splunkSecret) //nolint
})

It("should pass if only IndexKey is spec'd", func() {
Expand All @@ -502,6 +601,7 @@ var _ = Describe("Validate clusterlogforwarderspec", func() {
IndexKey: "kubernetes.namespace_name",
},
},
Secret: &loggingv1.OutputSecretSpec{Name: splunkSecret.Name},
},
}
verifyOutputs(namespace, client, &forwarderSpec, clfStatus, extras)
Expand All @@ -520,6 +620,7 @@ var _ = Describe("Validate clusterlogforwarderspec", func() {
IndexName: "custom-index",
},
},
Secret: &loggingv1.OutputSecretSpec{Name: splunkSecret.Name},
},
}
verifyOutputs(namespace, client, &forwarderSpec, clfStatus, extras)
Expand All @@ -534,6 +635,7 @@ var _ = Describe("Validate clusterlogforwarderspec", func() {
Type: loggingv1.OutputTypeSplunk,
URL: "https://splunk-web:8088/endpoint",
OutputTypeSpec: loggingv1.OutputTypeSpec{},
Secret: &loggingv1.OutputSecretSpec{Name: splunkSecret.Name},
},
}
verifyOutputs(namespace, client, &forwarderSpec, clfStatus, extras)
Expand All @@ -553,6 +655,7 @@ var _ = Describe("Validate clusterlogforwarderspec", func() {
IndexName: "custom-index",
},
},
Secret: &loggingv1.OutputSecretSpec{Name: splunkSecret.Name},
},
}
verifyOutputs(namespace, client, &forwarderSpec, clfStatus, extras)
Expand Down