This is an automated email from the ASF dual-hosted git repository.

HoustonPutman pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr-operator.git


The following commit(s) were added to refs/heads/main by this push:
     new 135e009  Various fixes and improvements
135e009 is described below

commit 135e00903d0b050f6259e197c21aa036bc57fe10
Author: Houston Putman <[email protected]>
AuthorDate: Mon Oct 26 14:19:03 2026 -0700

    Various fixes and improvements
---
 .dockerignore                               | 38 ++++++++++++++++++++++++++
 tests/e2e/solrcloud_rolling_upgrade_test.go | 22 ++++++++-------
 tests/e2e/suite_test.go                     | 42 ++++++++++++++++++++++-------
 3 files changed, 83 insertions(+), 19 deletions(-)

diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..290ba64
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,38 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+# The operator image (build/Dockerfile) only needs a small, well-defined set 
of paths. Ignore everything and
+# then re-include exactly what the Dockerfile COPYs, so unrelated changes 
(tests, docs, helm, IDE files, the
+# local bin/ toolchain, etc.) never enter the build context or invalidate the 
build cache.
+# Keep this allowlist in sync with the COPY instructions in build/Dockerfile.
+*
+
+# Go modules (downloaded before source is copied, to cache dependencies)
+!go.mod
+!go.sum
+
+# Git metadata and build tooling used during the image build
+!.git
+!build
+!hack
+!Makefile
+!LICENSE
+!NOTICE
+
+# Operator source
+!main.go
+!version
+!api
+!controllers
diff --git a/tests/e2e/solrcloud_rolling_upgrade_test.go 
b/tests/e2e/solrcloud_rolling_upgrade_test.go
index 55b6d3b..d80d21d 100644
--- a/tests/e2e/solrcloud_rolling_upgrade_test.go
+++ b/tests/e2e/solrcloud_rolling_upgrade_test.go
@@ -19,6 +19,8 @@ package e2e
 
 import (
        "context"
+       "time"
+
        solrv1beta1 "github.com/apache/solr-operator/api/v1beta1"
        "github.com/apache/solr-operator/controllers"
        . "github.com/onsi/ginkgo/v2"
@@ -27,7 +29,6 @@ import (
        corev1 "k8s.io/api/core/v1"
        "k8s.io/apimachinery/pkg/util/intstr"
        "sigs.k8s.io/controller-runtime/pkg/client"
-       "time"
 )
 
 var _ = FDescribe("E2E - SolrCloud - Rolling Upgrades", func() {
@@ -154,14 +155,17 @@ var _ = FDescribe("E2E - SolrCloud - Rolling Upgrades", 
func() {
                                
g.Expect(clusterOp.Metadata).To(Equal("RollingUpdateComplete"), "StatefulSet 
balanceReplicas lock operation has the wrong metadata.")
                        })
 
-                       // After all pods are ready, make sure that the 
SolrCloud status is correct
-                       solrCloud = expectSolrCloud(ctx, solrCloud)
-                       
Expect(solrCloud.Status.ReadyReplicas).To(Equal(solrCloud.Status.UpToDateNodes),
 "The SolrCloud did not finish the rolling restart, all nodes are up-to-date, 
but not all are ready")
-                       // Make sure that the status object is correct for the 
nodes
-                       for _, nodeStatus := range solrCloud.Status.SolrNodes {
-                               Expect(nodeStatus.SpecUpToDate).To(BeTrue(), 
"Node not finishing as up-to-date when rolling restart ends: %s", 
nodeStatus.Name)
-                               Expect(nodeStatus.Ready).To(BeTrue(), "Node not 
finishing as ready when rolling restart ends: %s", nodeStatus.Name)
-                       }
+                       // After all pods are ready, make sure that the 
SolrCloud status is correct.
+                       // The status is written by a separate reconcile than 
the one that sees the StatefulSet become ready,
+                       // so give it a moment to catch up.
+                       solrCloud = expectSolrCloudWithChecksAndTimeout(ctx, 
solrCloud, time.Second, time.Millisecond*100, func(g Gomega, found 
*solrv1beta1.SolrCloud) {
+                               
g.Expect(found.Status.ReadyReplicas).To(Equal(found.Status.UpToDateNodes), "The 
SolrCloud did not finish the rolling restart, all nodes are up-to-date, but not 
all are ready")
+                               // Make sure that the status object is correct 
for the nodes
+                               for _, nodeStatus := range 
found.Status.SolrNodes {
+                                       
g.Expect(nodeStatus.SpecUpToDate).To(BeTrue(), "Node not finishing as 
up-to-date when rolling restart ends: %s", nodeStatus.Name)
+                                       g.Expect(nodeStatus.Ready).To(BeTrue(), 
"Node not finishing as ready when rolling restart ends: %s", nodeStatus.Name)
+                               }
+                       })
 
                        By("waiting for the balanceReplicas to finish")
                        expectStatefulSetWithChecksAndTimeout(ctx, solrCloud, 
solrCloud.StatefulSetName(), time.Second*70, time.Second, func(g Gomega, found 
*appsv1.StatefulSet) {
diff --git a/tests/e2e/suite_test.go b/tests/e2e/suite_test.go
index b63d227..053ca6c 100644
--- a/tests/e2e/suite_test.go
+++ b/tests/e2e/suite_test.go
@@ -501,17 +501,39 @@ func writeAllPodInfoToFiles(ctx context.Context, 
baseFilename string, pod *corev
        _, writeErr = eventsFile.Write(jsonBytes)
        Expect(writeErr).ToNot(HaveOccurred(), "Could not write pod events json 
to file")
 
-       // Write pod logs to a file
-       if len(pod.Status.ContainerStatuses) > 0 && 
pod.Status.ContainerStatuses[0].Started != nil && 
*pod.Status.ContainerStatuses[0].Started {
-               writePodLogsToFile(
-                       ctx,
-                       baseFilename+".log",
-                       pod.Name,
-                       pod.Namespace,
-                       nil,
-                       "",
-               )
+       // Write logs for every container that has run, including init 
containers and containers that crashed.
+       // A crash-looping container is in the "waiting" state, so we can't 
rely on it currently running.
+       allContainerStatuses := append(append([]corev1.ContainerStatus{}, 
pod.Status.InitContainerStatuses...), pod.Status.ContainerStatuses...)
+       for _, containerStatus := range allContainerStatuses {
+               containerBaseFilename := baseFilename + "." + 
containerStatus.Name
+               if containerStatus.State.Running != nil || 
containerStatus.State.Terminated != nil || containerStatus.RestartCount > 0 {
+                       writeContainerLogsToFile(ctx, 
containerBaseFilename+".log", pod, containerStatus.Name, false)
+               }
+               // The logs of the last crashed instance are only available via 
the "previous" option
+               if containerStatus.RestartCount > 0 || 
containerStatus.LastTerminationState.Terminated != nil {
+                       writeContainerLogsToFile(ctx, 
containerBaseFilename+".previous.log", pod, containerStatus.Name, true)
+               }
+       }
+}
+
+// writeContainerLogsToFile saves the logs of a single container to the given 
file.
+// Failing to fetch the logs does not fail the test, since this is only used 
to collect debugging information.
+// The error is written to the file instead, so that it is clear why the logs 
are empty.
+func writeContainerLogsToFile(ctx context.Context, filename string, pod 
*corev1.Pod, containerName string, previous bool) {
+       logFile, err := os.Create(filename)
+       Expect(err).ToNot(HaveOccurred(), "Could not open file to save logs: 
%s", filename)
+       defer logFile.Close()
+
+       podLogOpts := corev1.PodLogOptions{Container: containerName, Previous: 
previous}
+       podLogs, logsErr := 
rawK8sClient.CoreV1().Pods(pod.Namespace).GetLogs(pod.Name, 
&podLogOpts).Stream(ctx)
+       if logsErr != nil {
+               _, _ = fmt.Fprintf(logFile, "Could not fetch logs for container 
%q (previous=%t) of pod %q: %v\n", containerName, previous, pod.Name, logsErr)
+               return
        }
+       defer podLogs.Close()
+
+       _, err = io.Copy(logFile, podLogs)
+       Expect(err).ToNot(HaveOccurred(), "Could not write container logs to 
file: %s", filename)
 }
 
 func writePodLogsToFile(ctx context.Context, filename string, podName string, 
podNamespace string, startTimeRaw *time.Time, filterLinesWithString string) {

Reply via email to