diff --git a/cmd/main.go b/cmd/main.go index 063f6d4..903964e 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -35,7 +35,7 @@ import ( metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" armadav1 "opendev.org/airship/armada-operator/api/v1" - "opendev.org/airship/armada-operator/internal/controller" + "opendev.org/airship/armada-operator/pkg/controller" //+kubebuilder:scaffold:imports ) diff --git a/images/armada-operator/Dockerfile.ubuntu_focal b/images/armada-operator/Dockerfile.ubuntu_focal index 73ad0a1..6ee7003 100644 --- a/images/armada-operator/Dockerfile.ubuntu_focal +++ b/images/armada-operator/Dockerfile.ubuntu_focal @@ -15,7 +15,7 @@ RUN go mod download # Copy the go source COPY cmd/main.go cmd/main.go COPY api/ api/ -COPY internal/ internal/ +COPY pkg/ pkg/ # Build # the GOARCH has not a default value to allow the binary be built according to the host where the command diff --git a/internal/controller/armadachart_controller.go b/pkg/controller/armadachart_controller.go similarity index 98% rename from internal/controller/armadachart_controller.go rename to pkg/controller/armadachart_controller.go index 62e9658..2f58ac0 100644 --- a/internal/controller/armadachart_controller.go +++ b/pkg/controller/armadachart_controller.go @@ -47,8 +47,9 @@ import ( "sigs.k8s.io/controller-runtime/pkg/predicate" armadav1 "opendev.org/airship/armada-operator/api/v1" - "opendev.org/airship/armada-operator/internal/kube" - "opendev.org/airship/armada-operator/internal/runner" + "opendev.org/airship/armada-operator/pkg/kube" + "opendev.org/airship/armada-operator/pkg/runner" + "opendev.org/airship/armada-operator/pkg/waitutil" ) // ArmadaChartReconciler reconciles a ArmadaChart object @@ -276,8 +277,8 @@ func (r *ArmadaChartReconciler) waitRelease(ctx context.Context, restCfg *rest.C } } - opts := kube.WaitOptions{ - RestConfig: *restCfg, + opts := waitutil.WaitOptions{ + RestConfig: restCfg, Namespace: hr.Spec.Namespace, LabelSelector: labelSelector, ResourceType: fmt.Sprintf("%ss", res.Type), @@ -408,7 +409,7 @@ func isUpdateRequired(ctx context.Context, release *release.Release, chrt *chart // return true case !cmp.Equal(release.Config, vals.AsMap(), cmpopts.EquateEmpty()): - log.Info("There are CHART VALUES diffs") + log.Info("There are chart values diffs found") log.Info(cmp.Diff(release.Config, vals.AsMap(), cmpopts.EquateEmpty())) return true } diff --git a/internal/controller/suite_test.go b/pkg/controller/suite_test.go similarity index 100% rename from internal/controller/suite_test.go rename to pkg/controller/suite_test.go diff --git a/internal/kube/client.go b/pkg/kube/client.go similarity index 100% rename from internal/kube/client.go rename to pkg/kube/client.go diff --git a/internal/runner/log_buffer.go b/pkg/runner/log_buffer.go similarity index 100% rename from internal/runner/log_buffer.go rename to pkg/runner/log_buffer.go diff --git a/internal/runner/runner.go b/pkg/runner/runner.go similarity index 100% rename from internal/runner/runner.go rename to pkg/runner/runner.go diff --git a/internal/kube/wait.go b/pkg/waitutil/wait.go similarity index 88% rename from internal/kube/wait.go rename to pkg/waitutil/wait.go index 240ed3f..2801f59 100644 --- a/internal/kube/wait.go +++ b/pkg/waitutil/wait.go @@ -14,13 +14,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -package kube +package waitutil import ( "context" "errors" "fmt" - "io" "math" "strconv" "strings" @@ -38,6 +37,8 @@ import ( "k8s.io/client-go/rest" "k8s.io/client-go/tools/cache" watchtools "k8s.io/client-go/tools/watch" + + armadav1 "opendev.org/airship/armada-operator/api/v1" ) type StatusType string @@ -61,12 +62,11 @@ const ( // WaitOptions phase run command type WaitOptions struct { - RestConfig rest.Config + RestConfig *rest.Config Namespace string LabelSelector string ResourceType string Timeout time.Duration - Out io.Writer MinReady string Logger logr.Logger } @@ -85,25 +85,25 @@ func getObjectStatus(obj interface{}, minReady *MinReady) Status { return isDaemonSetReady(v, minReady) case *appsv1.StatefulSet: return isStatefulSetReady(v, minReady) + case *armadav1.ArmadaChart: + return isArmadaChartReady(v) default: - return Status{Error, fmt.Sprintf("Unable to cast an object to any type %s\n", obj)} + return Status{Error, fmt.Sprintf("Unable to cast an object to any type %s", obj)} } } func allMatch(logger logr.Logger, store cache.Store, minReady *MinReady, obj runtime.Object) (bool, error) { - logger.Info(fmt.Sprintf("verifying ready status for %d number of objects", len(store.List()))) for _, item := range store.List() { if obj != nil && item == obj { - logger.Info(fmt.Sprintf("Skipping the item as status is already computed")) continue } status := getObjectStatus(item, minReady) - logger.Info(fmt.Sprintf("object %T status computed: %s %s\n", item, status.StatusType, status.Msg)) + logger.Info(fmt.Sprintf("object %T status computed: %s %s", item, status.StatusType, status.Msg)) if status.StatusType != Ready && status.StatusType != Skipped { return false, nil } } - logger.Info("all objects are ready\n") + logger.Info("all objects are ready") return true, nil } @@ -125,6 +125,17 @@ func processEvent(logger logr.Logger, event watch.Event, minReady *MinReady) (St return status.StatusType, nil } +func isArmadaChartReady(ac *armadav1.ArmadaChart) Status { + if ac.Status.ObservedGeneration == ac.Generation { + for _, cond := range ac.Status.Conditions { + if cond.Type == "Ready" && cond.Status == "True" { + return Status{Ready, fmt.Sprintf("armadachart %s ready", ac.GetName())} + } + } + } + return Status{Unready, fmt.Sprintf("Waiting for armadachart %s to be ready", ac.GetName())} +} + func isPodReady(pod *corev1.Pod) Status { if isTestPod(pod) || pod.Status.Phase == "Evicted" || hasOwner(&pod.ObjectMeta, "Job") { return Status{Skipped, @@ -174,7 +185,7 @@ func isDeploymentReady(deployment *appsv1.Deployment, minReady *MinReady) Status if gen <= observed { for _, cond := range status.Conditions { if cond.Type == "Progressing" && cond.Reason == "ProgressDeadlineExceeded" { - return Status{Unready, fmt.Sprintf("Deployment %s exceeded its progress deadline\n", name)} + return Status{Unready, fmt.Sprintf("Deployment %s exceeded its progress deadline", name)} } } replicas := int32(0) @@ -185,12 +196,12 @@ func isDeploymentReady(deployment *appsv1.Deployment, minReady *MinReady) Status available := status.AvailableReplicas if updated < replicas { return Status{Unready, fmt.Sprintf("Waiting for deployment %s rollout to finish: %d"+ - " out of %d new replicas have been updated...\n", name, updated, replicas)} + " out of %d new replicas have been updated...", name, updated, replicas)} } if replicas > updated { pending := replicas - updated return Status{Unready, fmt.Sprintf("Waiting for deployment %s rollout to finish: %d old "+ - "replicas are pending termination...\n", name, pending)} + "replicas are pending termination...", name, pending)} } if minReady.Percent { @@ -199,13 +210,13 @@ func isDeploymentReady(deployment *appsv1.Deployment, minReady *MinReady) Status if available < minReady.int32 { return Status{Unready, fmt.Sprintf("Waiting for deployment %s rollout to finish: %d of %d "+ - "updated replicas are available, with min_ready=%d\n", name, available, updated, minReady.int32)} + "updated replicas are available, with min_ready=%d", name, available, updated, minReady.int32)} } - return Status{Ready, fmt.Sprintf("deployment %s successfully rolled out\n", name)} + return Status{Ready, fmt.Sprintf("deployment %s successfully rolled out", name)} } - return Status{Unready, fmt.Sprintf("Waiting for deployment %s spec update to be observed...\n", name)} + return Status{Unready, fmt.Sprintf("Waiting for deployment %s spec update to be observed...", name)} } func isDaemonSetReady(daemonSet *appsv1.DaemonSet, minReady *MinReady) Status { @@ -302,6 +313,10 @@ func hasOwner(ometa *metav1.ObjectMeta, kind string) bool { } func getClient(resource string, config *rest.Config) (rest.Interface, error) { + if resource == "armadacharts" { + return armadav1.NewForConfig(config) + } + cs, err := kubernetes.NewForConfig(config) if err != nil { return nil, err @@ -337,9 +352,9 @@ func getMinReady(minReady string) (*MinReady, error) { } func (c *WaitOptions) Wait(parent context.Context) error { - c.Logger.Info(fmt.Sprintf("armada-operator wait , namespace %s labels %s type %s timeout %s", c.Namespace, c.LabelSelector, c.ResourceType, c.Timeout)) + c.Logger.Info(fmt.Sprintf("starting wait for resources: namespace %s labels %s type %s timeout %s", c.Namespace, c.LabelSelector, c.ResourceType, c.Timeout)) - clientSet, err := getClient(c.ResourceType, &c.RestConfig) + clientSet, err := getClient(c.ResourceType, c.RestConfig) if err != nil { return err } @@ -349,7 +364,6 @@ func (c *WaitOptions) Wait(parent context.Context) error { lw := cache.NewFilteredListWatchFromClient(clientSet, c.ResourceType, c.Namespace, func(options *metav1.ListOptions) { options.LabelSelector = c.LabelSelector - c.Logger.Info(fmt.Sprintf("Label selector applied %s", options)) }) minReady, err := getMinReady(c.MinReady) @@ -363,7 +377,7 @@ func (c *WaitOptions) Wait(parent context.Context) error { cacheStore = store c.Logger.Info(fmt.Sprintf("number of objects to watch: %d", len(store.List()))) if len(store.List()) == 0 { - c.Logger.Info(fmt.Sprintf("Skipping non-required wait, no resources found.\n")) + c.Logger.Info(fmt.Sprintf("Skipping non-required wait, no resources found")) return true, nil } return allMatch(c.Logger, cacheStore, minReady, nil)