diff --git a/Dockerfile b/Dockerfile index 1ba5bb6e2..6b75560d2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -36,7 +36,7 @@ COPY internal/ internal/ # was called. For example, if we call make docker-build in a local env which has the Apple Silicon M1 SO # the docker BUILDPLATFORM arg will be linux/arm64 when for Apple x86 it will be linux/amd64. Therefore, # by leaving it empty we can ensure that the container and binary shipped on it will have the same platform. -RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -ldflags="${LD_FLAGS}" -a -o manager cmd/main.go +RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -gcflags=all="-N -l" -ldflags="${LD_FLAGS}" -a -o manager cmd/main.go # Use distroless as minimal base image to package the manager binary # Refer to https://github.com/GoogleContainerTools/distroless for more details diff --git a/Makefile b/Makefile index fd18a36ca..ae68421bd 100644 --- a/Makefile +++ b/Makefile @@ -141,8 +141,7 @@ lint-chart-%: package-chart-%: $(CHARTS_PACKAGE_DIR) lint-chart-% $(HELM) package --destination $(CHARTS_PACKAGE_DIR) $(TEMPLATES_DIR)/$* -LD_FLAGS?= -s -w -LD_FLAGS += -X github.com/Mirantis/hmc/internal/build.Version=$(VERSION) +LD_FLAGS = -X github.com/Mirantis/hmc/internal/build.Version=$(VERSION) LD_FLAGS += -X github.com/Mirantis/hmc/internal/telemetry.segmentToken=$(SEGMENT_TOKEN) .PHONY: build diff --git a/config/dev/deployment.yaml b/config/dev/deployment.yaml index 58ba18e32..da64faeee 100644 --- a/config/dev/deployment.yaml +++ b/config/dev/deployment.yaml @@ -1,17 +1,17 @@ apiVersion: hmc.mirantis.com/v1alpha1 kind: Deployment metadata: - name: aws-dev + name: tbone-aws-dev spec: template: aws-standalone-cp config: - region: us-east-2 + region: us-west-1 publicIP: true controlPlaneNumber: 1 workersNumber: 1 controlPlane: - amiID: ami-02f3416038bdb17fb + amiID: ami-0e99d1e59ff320ab2 instanceType: t3.small worker: - amiID: ami-02f3416038bdb17fb + amiID: ami-0e99d1e59ff320ab2 instanceType: t3.small diff --git a/internal/controller/deployment_controller.go b/internal/controller/deployment_controller.go index b83ac7192..31972f4e3 100644 --- a/internal/controller/deployment_controller.go +++ b/internal/controller/deployment_controller.go @@ -16,7 +16,6 @@ package controller import ( "context" - "encoding/json" "errors" "fmt" "time" @@ -31,6 +30,7 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" apimeta "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" @@ -89,12 +89,7 @@ func (r *DeploymentReconciler) Reconcile(ctx context.Context, req ctrl.Request) return r.Update(ctx, l, deployment) } -func (r *DeploymentReconciler) setStatusFromClusterStatus(ctx context.Context, l logr.Logger, deployment *hmc.Deployment) (bool, error) { - dc, err := dynamic.NewForConfig(r.Config) - if err != nil { - return true, fmt.Errorf("failed to create client configuration: %v", err) - } - +func (r *DeploymentReconciler) setStatusFromClusterStatus(ctx context.Context, dc *dynamic.DynamicClient, l logr.Logger, deployment *hmc.Deployment) (bool, error) { resourceId := schema.GroupVersionResource{ Group: "cluster.x-k8s.io", Version: "v1beta1", @@ -108,45 +103,52 @@ func (r *DeploymentReconciler) setStatusFromClusterStatus(ctx context.Context, l } if err != nil { - return true, fmt.Errorf("failed to get cluster information for deployment: %s: %w", deployment.Name, err) + return true, fmt.Errorf("failed to get cluster information for deployment %s in namespace: %s: %w", + deployment.Namespace, deployment.Name, err) + } + conditions, found, err := unstructured.NestedSlice(list.Object, "status", "conditions") + if err != nil { + return true, fmt.Errorf("failed to get cluster information for deployment %s in namespace: %s: %w", + deployment.Namespace, deployment.Name, err) + } + if !found { + return true, fmt.Errorf("failed to get cluster information for deployment %s in namespace: %s: status.conditions not found", + deployment.Namespace, deployment.Name) } - requeue := true - if statusField, ok := list.Object["status"]; ok { - if statusMap, ok := statusField.(map[string]interface{}); ok { - if conditionsField, ok := statusMap["conditions"]; ok { - bytes, err := json.Marshal(conditionsField) - if err != nil { - return true, fmt.Errorf("failed to get deserialize cluster information for deployment: %s : %v", - deployment.Name, err) - } - var conditions []metav1.Condition - err = json.Unmarshal(bytes, &conditions) - if err != nil { - return true, fmt.Errorf("failed to get serialize cluster information for deployment: %s : %v", - deployment.Name, err) - } + allConditionsComplete := true + for _, condition := range conditions { + conditionMap, ok := condition.(map[string]interface{}) + if !ok { + return true, fmt.Errorf("failed to cast condition to map[string]interface{} for deployment: %s in namespace: %s: %w", + deployment.Namespace, deployment.Name, err) + } - allConditionsComplete := true - for _, condition := range conditions { - if condition.Status != "True" { - allConditionsComplete = false - } + var metaCondition metav1.Condition + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(conditionMap, &metaCondition); err != nil { + return true, fmt.Errorf("failed to convert unstructured conditions to metav1.Condition for deployment %s in namespace: %s: %w", + deployment.Namespace, deployment.Name, err) + } - if condition.Reason == "" && condition.Status == "True" { - condition.Reason = "Succeeded" - } - apimeta.SetStatusCondition(deployment.GetConditions(), condition) - } - requeue = !allConditionsComplete - } + if metaCondition.Status != "True" { + allConditionsComplete = false + } + + if metaCondition.Reason == "" && metaCondition.Status == "True" { + metaCondition.Reason = "Succeeded" } + apimeta.SetStatusCondition(deployment.GetConditions(), metaCondition) } - return requeue, nil + return !allConditionsComplete, nil } func (r *DeploymentReconciler) Update(ctx context.Context, l logr.Logger, deployment *hmc.Deployment) (result ctrl.Result, err error) { + dc, err := dynamic.NewForConfig(r.Config) + if err != nil { + return ctrl.Result{}, fmt.Errorf("failed to create client configuration: %v", err) + } + finalizersUpdated := controllerutil.AddFinalizer(deployment, hmc.DeploymentFinalizer) if finalizersUpdated { if err := r.Client.Update(ctx, deployment); err != nil { @@ -284,7 +286,7 @@ func (r *DeploymentReconciler) Update(ctx context.Context, l logr.Logger, deploy }) } - requeue, err := r.setStatusFromClusterStatus(ctx, l, deployment) + requeue, err := r.setStatusFromClusterStatus(ctx, dc, l, deployment) if err != nil { if requeue { return ctrl.Result{RequeueAfter: 10 * time.Second}, err diff --git a/internal/controller/deployment_controller_test.go b/internal/controller/deployment_controller_test.go index 236ff5311..cd0cc1dba 100644 --- a/internal/controller/deployment_controller_test.go +++ b/internal/controller/deployment_controller_test.go @@ -25,6 +25,7 @@ import ( "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/reconcile" hmc "github.com/Mirantis/hmc/api/v1alpha1" @@ -128,6 +129,7 @@ var _ = Describe("Deployment Controller", func() { controllerReconciler := &DeploymentReconciler{ Client: k8sClient, Scheme: k8sClient.Scheme(), + Config: &rest.Config{}, } _, err := controllerReconciler.Reconcile(ctx, reconcile.Request{ diff --git a/templates/hmc/templates/deployment.yaml b/templates/hmc/templates/deployment.yaml index 028835a1a..81ba36d64 100644 --- a/templates/hmc/templates/deployment.yaml +++ b/templates/hmc/templates/deployment.yaml @@ -70,9 +70,9 @@ spec: readOnly: true {{- end }} securityContext: - runAsNonRoot: true + runAsNonRoot: false serviceAccountName: {{ include "hmc.fullname" . }}-controller-manager - terminationGracePeriodSeconds: 10 + terminationGracePeriodSeconds: 6000 {{- if .Values.admissionWebhook.enabled }} volumes: - name: cert