diff --git a/.github/workflows/aergia-controller.yaml b/.github/workflows/aergia-controller.yaml index 6900dc2..b22cbed 100644 --- a/.github/workflows/aergia-controller.yaml +++ b/.github/workflows/aergia-controller.yaml @@ -59,8 +59,8 @@ jobs: with: context: . load: true - tags: amazeeiolocal/aergia:test-tag + tags: uselagoonlocal/aergia:test-tag - name: Run Tests run: | - kind load docker-image amazeeiolocal/aergia:test-tag --name chart-testing + kind load docker-image uselagoonlocal/aergia:test-tag --name chart-testing make controller-test \ No newline at end of file diff --git a/.github/workflows/build_and_publish.yml b/.github/workflows/build_and_publish.yml index 664207d..752bda2 100644 --- a/.github/workflows/build_and_publish.yml +++ b/.github/workflows/build_and_publish.yml @@ -24,8 +24,8 @@ jobs: with: # list of Docker images to use as base name for tags images: | - amazeeio/aergia - ghcr.io/amazeeio/aergia + uselagoon/aergia + ghcr.io/uselagoon/aergia - name: Set up QEMU uses: docker/setup-qemu-action@v1 diff --git a/Makefile b/Makefile index 502bd07..36e8a9c 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ # Image URL to use all building/pushing image targets -IMG ?= amazeeiolocal/aergia:test-tag +IMG ?= uselagoonlocal/aergia:test-tag # Produce CRDs that work back to Kubernetes 1.11 (no version conversion) CRD_OPTIONS ?= "crd:trivialVersions=true" diff --git a/PROJECT b/PROJECT index 378056e..5127f14 100644 --- a/PROJECT +++ b/PROJECT @@ -1,3 +1,3 @@ -domain: amazee.io -repo: github.com/amazeeio/aergia-controller +domain: lagoon.sh +repo: github.com/uselagoon/aergia-controller version: "2" diff --git a/README.md b/README.md index b049367..2a1f95c 100644 --- a/README.md +++ b/README.md @@ -13,21 +13,21 @@ This backend is designed to serve generic error handling for any http error. The An environment can be force idled, force scaled, or unidled using labels on the namespace. All actions still respect the label selectors, but forced actions will bypass any hits checks ### Force Idled -To force idle a namespace, you can label the namespace using `idling.amazee.io/force-idled=true`. This will cause the environment to be immediately scaled down, but the next request to the ingress in the namespace will unidle the namespace +To force idle a namespace, you can label the namespace using `idling.lagoon.sh/force-idled=true`. This will cause the environment to be immediately scaled down, but the next request to the ingress in the namespace will unidle the namespace ### Force Scaled -To force scale a namespace, you can label the namespace using `idling.amazee.io/force-scaled=true`. This will cause the environment to be immediately scaled down, but the next request to the ingress in the namespace will *NOT* unidle the namespace. A a deployment will be required to unidle this namespace +To force scale a namespace, you can label the namespace using `idling.lagoon.sh/force-scaled=true`. This will cause the environment to be immediately scaled down, but the next request to the ingress in the namespace will *NOT* unidle the namespace. A a deployment will be required to unidle this namespace ### Unidle -To unidle a namespace, you can label the namespace using `idling.amazee.io/unidle=true`. This will cause the environment to be scaled back up to its previous state. +To unidle a namespace, you can label the namespace using `idling.lagoon.sh/unidle=true`. This will cause the environment to be scaled back up to its previous state. ### Idled -A label `idling.amazee.io/idled` is set that will be true or false depending on if the environment is idled. This ideally should not be modified as Aergia will update it as required. +A label `idling.lagoon.sh/idled` is set that will be true or false depending on if the environment is idled. This ideally should not be modified as Aergia will update it as required. ### Namespace Idling Overrides If you want to change a namespaces interval check times outside of the globally applied intervals, the following annotations can be added to the namespace -* `idling.amazee.io/prometheus-interval` - set this to the time interval for prometheus checks, the format must be in [30m|4h|1h30m](https://pkg.go.dev/time#ParseDuration) notation -* `idling.amazee.io/pod-interval` - set this to the time interval for pod uptime checks, the format must be in [30m|4h|1h30m](https://pkg.go.dev/time#ParseDuration) notation +* `idling.lagoon.sh/prometheus-interval` - set this to the time interval for prometheus checks, the format must be in [30m|4h|1h30m](https://pkg.go.dev/time#ParseDuration) notation +* `idling.lagoon.sh/pod-interval` - set this to the time interval for pod uptime checks, the format must be in [30m|4h|1h30m](https://pkg.go.dev/time#ParseDuration) notation ### IP Allow/Block Lists It is possible to add global IP allow and block lists, the helm chart will have support for handling this creation @@ -35,8 +35,8 @@ It is possible to add global IP allow and block lists, the helm chart will have * blocking IP addresses via `/lists/blockedips` file which is a single line per entry of ip address to block There are also annotations that can be added to the namespace, or individual `Kind: Ingress` objects that allow for ip allow or blocking. -* `idling.amazee.io/ip-allow-list` - a comma separated list of ip addresses to allow, will be checked against x-forward-for, but if true-client-ip is provided it will prefer this. -* `idling.amazee.io/ip-block-list` - a comma separated list of ip addresses to allow, will be checked against x-forward-for, but if true-client-ip is provided it will prefer this. +* `idling.lagoon.sh/ip-allow-list` - a comma separated list of ip addresses to allow, will be checked against x-forward-for, but if true-client-ip is provided it will prefer this. +* `idling.lagoon.sh/ip-block-list` - a comma separated list of ip addresses to allow, will be checked against x-forward-for, but if true-client-ip is provided it will prefer this. ### UserAgent Allow/Block Lists It is possible to add global UserAgent allow and block lists, the helm chart will have support for handling this creation @@ -44,8 +44,8 @@ It is possible to add global UserAgent allow and block lists, the helm chart wil * blocking user agents via a `/lists/blockedagents` file which is a single line per entry of useragents or regex patterns to match against. These must be `go` based regular expressions. There are also annotations that can be added to the namespace, or individual `Kind: Ingress` objects that allow for user agent allow or blocking. -* `idling.amazee.io/allowed-agents` - a comma separated list of user agents or regex patterns to allow. -* `idling.amazee.io/blocked-agents` - a comma separated list of user agents or regex patterns to block. +* `idling.lagoon.sh/allowed-agents` - a comma separated list of user agents or regex patterns to allow. +* `idling.lagoon.sh/blocked-agents` - a comma separated list of user agents or regex patterns to block. ### Verify Unidling Requests It is possible to start Aergia in a mode where it will require unidling requests to be verified. The way this works is by using HMAC and passing the signed version of the requested namespace back to the user when the initial request to unidle the environment is received. When a client loads this page, it will execute a javascript query back to the requested ingress which is then verified by Aergia. If verification suceeds, it proceeds to unidle the environment. This functionality can be useful to prevent bots and other systems that don't have the ability to execute javascript from unidling environments uncessarily. The signed namespace value will only work for the requested namespace. @@ -55,7 +55,7 @@ To enable this functionality, set the following: - `--verify-secret=use-your-own-secret` or envvar `VERIFY_SECRET=use-your-own-secret` If the verification feature is enabled, and you need to unidle environments using tools that can't execute javascript, then it is possible to allow a namespace to override the feature by adding the following annotation to the namespace. Using the other allow/blocking mechanisms can then be used to restrict how the environment can unidle if required. -* `idling.amazee.io/disable-request-verification=true` - set this to disable the hmac verification on a namespace if Aergia has unidling request verification turned on. +* `idling.lagoon.sh/disable-request-verification=true` - set this to disable the hmac verification on a namespace if Aergia has unidling request verification turned on. If you're using custom template overrides and enable this functionality, you will need to extend your `unidle.html` template with the additional changes to allow it to to perform the call back function or else environments will never unidle. See the bundled `unidle.html` file to see how this may differ from your custom templates. @@ -67,7 +67,7 @@ This could be done using a configmap and volume mount to any directory, then upd # Installation -Install via helm (https://github.com/amazeeio/charts/tree/main/charts/aergia) +Install via lagoon-remote helm chart. ## Custom templates If installing via helm, you can use this YAML in your values.yaml file and define the templates there. diff --git a/build-push.sh b/build-push.sh index 0c0f77c..a129334 100755 --- a/build-push.sh +++ b/build-push.sh @@ -1,5 +1,5 @@ #!/bin/bash -REPO=${2:-amazeeio} +REPO=${2:-uselagoon} TAG=${1:-latest} IMGNAME=${3:-aergia} echo "Creating image for $REPO/${IMGNAME}:$TAG and pushing to docker hub" diff --git a/controller-test.sh b/controller-test.sh index affcd2f..ca26b6c 100755 --- a/controller-test.sh +++ b/controller-test.sh @@ -63,7 +63,7 @@ echo -e "${GREEN}Check that force-idle label idles an environment${NOCOLOR}" kubectl -n example-nginx get pods echo -e "${GREEN}Request example-nginx app (should be 200)${NOCOLOR}" if curl -s -I -H "Host: aergia.localhost" http://localhost:8090/| grep -q "200 OK"; then - kubectl patch namespace example-nginx --type=merge --patch '{"metadata":{"labels":{"idling.amazee.io/force-idled":"true"}}}' + kubectl patch namespace example-nginx --type=merge --patch '{"metadata":{"labels":{"idling.lagoon.sh/force-idled":"true"}}}' sleep 15 echo -e "${GREEN}Check there are 0 example-nginx pods${NOCOLOR}" kubectl -n example-nginx get pods @@ -95,11 +95,11 @@ echo -e "${GREEN}Check that an idled environment can be unidled by label${NOCOLO kubectl -n example-nginx get pods echo -e "${GREEN}Request example-nginx app (should be 200)${NOCOLOR}" if curl -s -I -H "Host: aergia.localhost" http://localhost:8090/| grep -q "200 OK"; then - kubectl patch namespace example-nginx --type=merge --patch '{"metadata":{"labels":{"idling.amazee.io/force-idled":"true"}}}' + kubectl patch namespace example-nginx --type=merge --patch '{"metadata":{"labels":{"idling.lagoon.sh/force-idled":"true"}}}' sleep 15 echo -e "${GREEN}Check there are 0 example-nginx pods${NOCOLOR}" kubectl -n example-nginx get pods - kubectl patch namespace example-nginx --type=merge --patch '{"metadata":{"labels":{"idling.amazee.io/unidle":"true"}}}' + kubectl patch namespace example-nginx --type=merge --patch '{"metadata":{"labels":{"idling.lagoon.sh/unidle":"true"}}}' sleep 15 echo -e "${GREEN}Check there are 3 example-nginx pods${NOCOLOR}" kubectl -n example-nginx get pods diff --git a/controllers/idling_controller.go b/controllers/idling_controller.go index ebc4f4c..a82ca77 100644 --- a/controllers/idling_controller.go +++ b/controllers/idling_controller.go @@ -20,15 +20,19 @@ import ( "encoding/json" "fmt" - "github.com/amazeeio/aergia-controller/handlers/idler" - "github.com/amazeeio/aergia-controller/handlers/unidler" "github.com/go-logr/logr" + "github.com/uselagoon/aergia-controller/handlers/idler" + "github.com/uselagoon/aergia-controller/handlers/unidler" + "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/selection" "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + networkv1 "k8s.io/api/networking/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" ) @@ -49,13 +53,13 @@ func (r *IdlingReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr return ctrl.Result{}, ignoreNotFound(err) } - if val, ok := namespace.ObjectMeta.Labels["idling.amazee.io/force-scaled"]; ok && val == "true" { + if val, ok := namespace.ObjectMeta.Labels["idling.lagoon.sh/force-scaled"]; ok && val == "true" { opLog.Info(fmt.Sprintf("Force scaling environment %s", namespace.Name)) r.Idler.KubernetesServiceIdler(ctx, opLog, namespace, namespace.ObjectMeta.Labels[r.Idler.Selectors.NamespaceSelectorsLabels.ProjectName], false, true) nsMergePatch, _ := json.Marshal(map[string]interface{}{ "metadata": map[string]interface{}{ "labels": map[string]*string{ - "idling.amazee.io/force-scaled": nil, + "idling.lagoon.sh/force-scaled": nil, }, }, }) @@ -66,13 +70,13 @@ func (r *IdlingReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr return ctrl.Result{}, nil } - if val, ok := namespace.ObjectMeta.Labels["idling.amazee.io/force-idled"]; ok && val == "true" { + if val, ok := namespace.ObjectMeta.Labels["idling.lagoon.sh/force-idled"]; ok && val == "true" { opLog.Info(fmt.Sprintf("Force idling environment %s", namespace.Name)) r.Idler.KubernetesServiceIdler(ctx, opLog, namespace, namespace.ObjectMeta.Labels[r.Idler.Selectors.NamespaceSelectorsLabels.ProjectName], true, false) nsMergePatch, _ := json.Marshal(map[string]interface{}{ "metadata": map[string]interface{}{ "labels": map[string]*string{ - "idling.amazee.io/force-idled": nil, + "idling.lagoon.sh/force-idled": nil, }, }, }) @@ -83,13 +87,13 @@ func (r *IdlingReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr return ctrl.Result{}, nil } - if val, ok := namespace.ObjectMeta.Labels["idling.amazee.io/unidle"]; ok && val == "true" { + if val, ok := namespace.ObjectMeta.Labels["idling.lagoon.sh/unidle"]; ok && val == "true" { opLog.Info(fmt.Sprintf("Unidling environment %s", namespace.Name)) r.Unidler.Unidle(ctx, &namespace, opLog) nsMergePatch, _ := json.Marshal(map[string]interface{}{ "metadata": map[string]interface{}{ "labels": map[string]*string{ - "idling.amazee.io/unidle": nil, + "idling.lagoon.sh/unidle": nil, }, }, }) @@ -99,6 +103,169 @@ func (r *IdlingReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr } return ctrl.Result{}, nil } + + /* + convert old labels or annotations + */ + conversions := false + // if the converted-old-labels label is not set or not true, then run the conversion + if val, ok := namespace.ObjectMeta.Labels["idling.lagoon.sh/converted-old-labels"]; !ok || val != "true" { + // ingress + labelRequirements, _ := labels.NewRequirement("idling.amazee.io/idled", selection.Exists, []string{}) + listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ + client.InNamespace(namespace.Name), + client.MatchingLabelsSelector{ + Selector: labels.NewSelector().Add(*labelRequirements), + }, + }) + ingressList := &networkv1.IngressList{} + if err := r.List(ctx, ingressList, listOption); err != nil { + opLog.Error(err, fmt.Sprintf("Error getting ingress for namespace %s", namespace.ObjectMeta.Name)) + } else { + for _, ingress := range ingressList.Items { + ingressPatchAnnotations := map[string]interface{}{} + ingressMergePatch, _ := json.Marshal(map[string]interface{}{ + "metadata": map[string]interface{}{ + "annotations": ingressPatchAnnotations, + }, + }) + if val, ok := ingress.ObjectMeta.Annotations["idling.amazee.io/allowed-agents"]; ok { + ingressPatchAnnotations["idling.lagoon.sh/allowed-agents"] = val + ingressPatchAnnotations["idling.amazee.io/allowed-agents"] = nil + } + if val, ok := ingress.ObjectMeta.Annotations["idling.amazee.io/blocked-agents"]; ok { + ingressPatchAnnotations["idling.lagoon.sh/blocked-agents"] = val + ingressPatchAnnotations["idling.amazee.io/blocked-agents"] = nil + } + if val, ok := ingress.ObjectMeta.Annotations["idling.amazee.io/ip-allow-agents"]; ok { + ingressPatchAnnotations["idling.lagoon.sh/ip-allow-agents"] = val + ingressPatchAnnotations["idling.amazee.io/ip-allow-agents"] = nil + } + if val, ok := ingress.ObjectMeta.Annotations["idling.amazee.io/ip-block-agents"]; ok { + ingressPatchAnnotations["idling.lagoon.sh/ip-block-agents"] = val + ingressPatchAnnotations["idling.amazee.io/ip-block-agents"] = nil + } + if len(ingressPatchAnnotations) > 0 { + conversions = true + patchIngress := ingress.DeepCopy() + if err := r.Patch(ctx, patchIngress, client.RawPatch(types.MergePatchType, ingressMergePatch)); err != nil { + // log it but try and scale the rest of the deployments anyway (some idled is better than none?) + opLog.Info(fmt.Sprintf("Error patching ingress %s -%v", patchIngress.Name, err)) + } + } + } + } + + // deployments + labelRequirements1, _ := labels.NewRequirement("idling.amazee.io/watch", selection.Exists, []string{}) + listOption = (&client.ListOptions{}).ApplyOptions([]client.ListOption{ + client.InNamespace(namespace.Name), + client.MatchingLabelsSelector{ + Selector: labels.NewSelector().Add(*labelRequirements1), + }, + }) + deployments := &appsv1.DeploymentList{} + if err := r.List(ctx, deployments, listOption); err != nil { + opLog.Error(err, fmt.Sprintf("Error getting deployments for namespace %s", namespace.ObjectMeta.Name)) + } else { + for _, deployment := range deployments.Items { + deploymentPatchAnnotations := map[string]interface{}{} + deploymentPatchLabels := map[string]interface{}{} + deploymentMergePatch, _ := json.Marshal(map[string]interface{}{ + "metadata": map[string]interface{}{ + "labels": deploymentPatchLabels, + "annotations": deploymentPatchAnnotations, + }, + }) + if val, ok := deployment.ObjectMeta.Labels["idling.amazee.io/watch"]; ok { + deploymentPatchLabels["idling.lagoon.sh/watch"] = val + deploymentPatchLabels["idling.amazee.io/watch"] = nil + } + if _, ok := deployment.ObjectMeta.Annotations["idling.amazee.io/idled"]; ok { + deploymentPatchAnnotations["idling.lagoon.sh/idled"] = nil + deploymentPatchAnnotations["idling.amazee.io/idled"] = nil + } + if val, ok := deployment.ObjectMeta.Labels["idling.amazee.io/idled"]; ok { + deploymentPatchLabels["idling.lagoon.sh/idled"] = val + deploymentPatchLabels["idling.amazee.io/idled"] = nil + } + if val, ok := deployment.ObjectMeta.Labels["idling.amazee.io/force-scaled"]; ok { + deploymentPatchLabels["idling.lagoon.sh/force-scaled"] = val + deploymentPatchLabels["idling.amazee.io/force-scaled"] = nil + } + if val, ok := deployment.ObjectMeta.Labels["idling.amazee.io/force-idled"]; ok { + deploymentPatchLabels["idling.lagoon.sh/force-idled"] = val + deploymentPatchLabels["idling.amazee.io/force-idled"] = nil + } + if val, ok := deployment.ObjectMeta.Annotations["idling.amazee.io/idled-at"]; ok { + deploymentPatchAnnotations["idling.lagoon.sh/idled-at"] = val + deploymentPatchAnnotations["idling.amazee.io/idled-at"] = nil + } + if val, ok := deployment.ObjectMeta.Annotations["idling.amazee.io/unidle-replicas"]; ok { + deploymentPatchAnnotations["idling.lagoon.sh/unidle-replicas"] = val + deploymentPatchAnnotations["idling.amazee.io/unidle-replicas"] = nil + } + if len(deploymentPatchAnnotations) > 0 || len(deploymentPatchLabels) > 0 { + conversions = true + patchDeployment := deployment.DeepCopy() + if err := r.Patch(ctx, patchDeployment, client.RawPatch(types.MergePatchType, deploymentMergePatch)); err != nil { + // log it but try and scale the rest of the deployments anyway (some idled is better than none?) + opLog.Info(fmt.Sprintf("Error patching deployment %s -%v", patchDeployment.Name, err)) + } + } + } + } + } + // namespace labels and anotations + nsPatchLabels := map[string]interface{}{} + nsPatchAnnotations := map[string]interface{}{} + nsMergePatch, _ := json.Marshal(map[string]interface{}{ + "metadata": map[string]interface{}{ + "labels": nsPatchLabels, + "annotations": nsPatchAnnotations, + }, + }) + if val, ok := namespace.ObjectMeta.Annotations["idling.amazee.io/disable-request-verification"]; ok { + nsPatchAnnotations["idling.lagoon.sh/disable-request-verification"] = val + nsPatchAnnotations["idling.amazee.io/disable-request-verification"] = nil + } + if val, ok := namespace.ObjectMeta.Annotations["idling.amazee.io/allowed-agents"]; ok { + nsPatchAnnotations["idling.lagoon.sh/allowed-agents"] = val + nsPatchAnnotations["idling.amazee.io/allowed-agents"] = nil + } + if val, ok := namespace.ObjectMeta.Annotations["idling.amazee.io/blocked-agents"]; ok { + nsPatchAnnotations["idling.lagoon.sh/blocked-agents"] = val + nsPatchAnnotations["idling.amazee.io/blocked-agents"] = nil + } + if val, ok := namespace.ObjectMeta.Annotations["idling.amazee.io/ip-allow-agents"]; ok { + nsPatchAnnotations["idling.lagoon.sh/ip-allow-agents"] = val + nsPatchAnnotations["idling.amazee.io/ip-allow-agents"] = nil + } + if val, ok := namespace.ObjectMeta.Annotations["idling.amazee.io/ip-block-agents"]; ok { + nsPatchAnnotations["idling.lagoon.sh/ip-block-agents"] = val + nsPatchAnnotations["idling.amazee.io/ip-block-agents"] = nil + } + if val, ok := namespace.ObjectMeta.Annotations["idling.amazee.io/prometheus-interval"]; ok { + nsPatchAnnotations["idling.lagoon.sh/prometheus-interval"] = val + nsPatchAnnotations["idling.amazee.io/prometheus-interval"] = nil + } + if val, ok := namespace.ObjectMeta.Annotations["idling.amazee.io/pod-interval"]; ok { + nsPatchAnnotations["idling.lagoon.sh/pod-interval"] = val + nsPatchAnnotations["idling.amazee.io/pod-interval"] = nil + } + if conversions { + // if any conversions took place, set the label to prevent further conversions taking place + nsPatchLabels["idling.lagoon.sh/converted-old-labels"] = true + } + if len(nsPatchLabels) > 0 || len(nsPatchAnnotations) > 0 { + if err := r.Patch(ctx, &namespace, client.RawPatch(types.MergePatchType, nsMergePatch)); err != nil { + // log it but try and scale the rest of the deployments anyway (some idled is better than none?) + opLog.Info(fmt.Sprintf("Error patching namespace %s -%v", namespace.Name, err)) + } + } + /* + convert old labels + */ return ctrl.Result{}, nil } diff --git a/go.mod b/go.mod index 5c4826c..222d482 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/amazeeio/aergia-controller +module github.com/uselagoon/aergia-controller go 1.21 diff --git a/handlers/idler/cli-kubernetes.go b/handlers/idler/cli-kubernetes.go index e05170a..74f2281 100644 --- a/handlers/idler/cli-kubernetes.go +++ b/handlers/idler/cli-kubernetes.go @@ -34,7 +34,7 @@ func (h *Idler) kubernetesCLI(ctx context.Context, opLog logr.Logger, namespace } else { for _, build := range builds.Items { if build.Status.Phase == "Running" { - opLog.Info(fmt.Sprintf("Environment has running build, skipping")) + opLog.Info("Environment has running build, skipping") runningBuild = true break } @@ -53,7 +53,7 @@ func (h *Idler) kubernetesCLI(ctx context.Context, opLog logr.Logger, namespace }) deployments := &appsv1.DeploymentList{} if err := h.Client.List(ctx, deployments, listOption); err != nil { - opLog.Error(err, fmt.Sprintf("Error getting deployments")) + opLog.Error(err, "Error getting deployments") } else { for _, deployment := range deployments.Items { // if we have any services=cli, act on them @@ -94,7 +94,7 @@ func (h *Idler) kubernetesCLI(ctx context.Context, opLog logr.Logger, namespace }, }) if err := h.Client.List(ctx, pods, listOption); err != nil { - opLog.Error(err, fmt.Sprintf("Error listing pods")) + opLog.Error(err, "Error listing pods") } else { for _, pod := range pods.Items { processCount := 0 diff --git a/handlers/idler/cli.go b/handlers/idler/cli.go index 115a292..83ff10a 100644 --- a/handlers/idler/cli.go +++ b/handlers/idler/cli.go @@ -28,7 +28,7 @@ func (h *Idler) CLIIdler() { }) namespaces := &corev1.NamespaceList{} if err := h.Client.List(ctx, namespaces, listOption); err != nil { - opLog.Error(err, fmt.Sprintf("unable to get any namespaces")) + opLog.Error(err, "unable to get any namespaces") return } for _, namespace := range namespaces.Items { @@ -40,7 +40,7 @@ func (h *Idler) CLIIdler() { WithValues("project", namespace.ObjectMeta.Labels[h.Selectors.NamespaceSelectorsLabels.ProjectName]). WithValues("environment", namespace.ObjectMeta.Labels[h.Selectors.NamespaceSelectorsLabels.EnvironmentName]). WithValues("dry-run", h.DryRun) - envOpLog.Info(fmt.Sprintf("Checking namespace")) + envOpLog.Info("Checking namespace") h.kubernetesCLI(ctx, envOpLog, namespace) } else { if h.Debug { diff --git a/handlers/idler/handler.go b/handlers/idler/handler.go index 6afc0d4..0981f4e 100644 --- a/handlers/idler/handler.go +++ b/handlers/idler/handler.go @@ -2,6 +2,7 @@ package idler import ( "bytes" + "context" "fmt" "io" "time" @@ -121,7 +122,7 @@ func execPod( } var stdout, stderr bytes.Buffer - err = exec.Stream(remotecommand.StreamOptions{ + err = exec.StreamWithContext(context.Background(), remotecommand.StreamOptions{ Stdin: stdin, Stdout: &stdout, Stderr: &stderr, diff --git a/handlers/idler/helpers.go b/handlers/idler/helpers.go index 7c4a7ba..04fc595 100644 --- a/handlers/idler/helpers.go +++ b/handlers/idler/helpers.go @@ -1,7 +1,6 @@ package idler import ( - "gopkg.in/yaml.v2" "k8s.io/apimachinery/pkg/labels" ) @@ -10,17 +9,6 @@ func generateSelector(s idlerSelector) *labels.Requirement { return r } -func yamlGenerateLabelRequirements(selectors []byte) []labels.Requirement { - labelRequirements := []labels.Requirement{} - convertedYaml := []idlerSelector{} - _ = yaml.Unmarshal([]byte(selectors), &convertedYaml) - for _, rs := range convertedYaml { - selector := generateSelector(rs) - labelRequirements = append(labelRequirements, *selector) - } - return labelRequirements -} - func generateLabelRequirements(selectors []idlerSelector) []labels.Requirement { labelRequirements := []labels.Requirement{} for _, rs := range selectors { @@ -29,9 +17,3 @@ func generateLabelRequirements(selectors []idlerSelector) []labels.Requirement { } return labelRequirements } - -func yamlToIdler(selectors []byte) Data { - convertedYaml := Data{} - _ = yaml.Unmarshal([]byte(selectors), &convertedYaml) - return convertedYaml -} diff --git a/handlers/idler/service-kubernetes.go b/handlers/idler/service-kubernetes.go index dec18f0..81cc27c 100644 --- a/handlers/idler/service-kubernetes.go +++ b/handlers/idler/service-kubernetes.go @@ -31,14 +31,13 @@ func (h *Idler) KubernetesServiceIdler(ctx context.Context, opLog logr.Logger, n podIntervalCheck := h.PodCheckInterval prometheusInternalCheck := h.PrometheusCheckInterval // allow namespace interval overides - if podinterval, ok := namespace.ObjectMeta.Annotations["idling.amazee.io/pod-interval"]; ok { + if podinterval, ok := namespace.ObjectMeta.Annotations["idling.lagoon.sh/pod-interval"]; ok { t, err := time.ParseDuration(podinterval) if err == nil { podIntervalCheck = t } - } - if promethusinterval, ok := namespace.ObjectMeta.Annotations["idling.amazee.io/prometheus-interval"]; ok { + if promethusinterval, ok := namespace.ObjectMeta.Annotations["idling.lagoon.sh/prometheus-interval"]; ok { t, err := time.ParseDuration(promethusinterval) if err == nil { prometheusInternalCheck = t @@ -53,7 +52,7 @@ func (h *Idler) KubernetesServiceIdler(ctx context.Context, opLog logr.Logger, n for _, build := range builds.Items { if build.Status.Phase == "Running" || build.Status.Phase == "Pending" { // if we have any pending builds, break out of this loop and try the next namespace - opLog.Info(fmt.Sprintf("Environment has running build, skipping")) + opLog.Info("Environment has running build, skipping") runningBuild = true break } @@ -73,7 +72,7 @@ func (h *Idler) KubernetesServiceIdler(ctx context.Context, opLog logr.Logger, n deployments := &appsv1.DeploymentList{} if err := h.Client.List(ctx, deployments, listOption); err != nil { // if we can't get any deployment configs for this namespace, log it and move on to the next - opLog.Error(err, fmt.Sprintf("Error getting deployments")) + opLog.Error(err, "Error getting deployments") return } for _, deployment := range deployments.Items { @@ -97,13 +96,13 @@ func (h *Idler) KubernetesServiceIdler(ctx context.Context, opLog logr.Logger, n }) if err := h.Client.List(ctx, pods, listOption); err != nil { // if we can't get any pods for this deployment, log it and move on to the next - opLog.Error(err, fmt.Sprintf("Error listing pods")) + opLog.Error(err, "Error listing pods") break } for _, pod := range pods.Items { // check if the runtime of the pod is more than our interval if pod.Status.StartTime != nil { - hs := time.Now().Sub(pod.Status.StartTime.Time) + hs := time.Since(pod.Status.StartTime.Time) if h.Debug { opLog.Info(fmt.Sprintf("Pod %s has been running for %v", pod.ObjectMeta.Name, hs)) } @@ -119,7 +118,7 @@ func (h *Idler) KubernetesServiceIdler(ctx context.Context, opLog logr.Logger, n if idle || forceIdle || forceScale { numHits := 0 if !h.Selectors.Service.SkipHitCheck && !forceIdle && !forceScale { - opLog.Info(fmt.Sprintf("Environment marked for idling, checking routerlogs for hits")) + opLog.Info("Environment marked for idling, checking routerlogs for hits") // query prometheus for hits to ingress resources in this namespace v1api := prometheusapiv1.NewAPI(h.PrometheusClient) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) @@ -149,7 +148,7 @@ func (h *Idler) KubernetesServiceIdler(ctx context.Context, opLog logr.Logger, n // if the hits are not 0, then the environment doesn't need to be idled opLog.Info(fmt.Sprintf("Environment has had %d hits in the last %s", numHits, prometheusInternalCheck)) if numHits != 0 { - opLog.Info(fmt.Sprintf("Environment does not need idling")) + opLog.Info("Environment does not need idling") return } } @@ -159,19 +158,17 @@ func (h *Idler) KubernetesServiceIdler(ctx context.Context, opLog logr.Logger, n err := h.patchIngress(ctx, opLog, namespace) if err != nil { // if patching the ingress resources fail, then don't idle the environment - opLog.Info(fmt.Sprintf("Environment not idled due to errors patching ingress")) + opLog.Info("Environment not idled due to errors patching ingress") return } - opLog.Info(fmt.Sprintf("Environment will be idled")) + opLog.Info("Environment will be idled") h.idleDeployments(ctx, opLog, deployments, forceIdle, forceScale) } } } func (h *Idler) idleDeployments(ctx context.Context, opLog logr.Logger, deployments *appsv1.DeploymentList, forceIdle, forceScale bool) { - d := []string{} for _, deployment := range deployments.Items { - d = append(d, deployment.ObjectMeta.Name) // @TODO: use the patch method for the k8s client for now, this seems to work just fine // Patching the deployment also works as we patch the endpoints below if !h.DryRun { @@ -184,16 +181,16 @@ func (h *Idler) idleDeployments(ctx context.Context, opLog logr.Logger, deployme idleReplicas = deployment.Spec.Replicas } scaleDeployment := deployment.DeepCopy() - labels := map[string]string{ + labels := map[string]interface{}{ // add the watch label so that the unidler knows to look at it - "idling.amazee.io/watch": "true", - "idling.amazee.io/idled": "true", + "idling.lagoon.sh/watch": "true", + "idling.lagoon.sh/idled": "true", } if forceIdle { - labels["idling.amazee.io/force-idled"] = "true" + labels["idling.lagoon.sh/force-idled"] = "true" } if forceScale { - labels["idling.amazee.io/force-scaled"] = "true" + labels["idling.lagoon.sh/force-scaled"] = "true" } mergePatch, _ := json.Marshal(map[string]interface{}{ "spec": map[string]interface{}{ @@ -201,10 +198,10 @@ func (h *Idler) idleDeployments(ctx context.Context, opLog logr.Logger, deployme }, "metadata": map[string]interface{}{ "labels": labels, - "annotations": map[string]string{ + "annotations": map[string]interface{}{ // add these annotations so user knows to look at them - "idling.amazee.io/idled-at": time.Now().Format(time.RFC3339), - "idling.amazee.io/unidle-replicas": strconv.FormatInt(int64(*idleReplicas), 10), + "idling.lagoon.sh/idled-at": time.Now().Format(time.RFC3339), + "idling.lagoon.sh/unidle-replicas": strconv.FormatInt(int64(*idleReplicas), 10), }, }, }) @@ -237,8 +234,8 @@ func (h *Idler) patchIngress(ctx context.Context, opLog logr.Logger, namespace c ingressList := &networkv1.IngressList{} if err := h.Client.List(ctx, ingressList, listOption); err != nil { // if we can't get any ingress for this namespace, log it and move on to the next - opLog.Error(err, fmt.Sprintf("Error getting ingress")) - return fmt.Errorf("Error getting ingress") + opLog.Error(err, "Error getting ingress") + return fmt.Errorf("error getting ingress") } patched := false for _, ingress := range ingressList.Items { @@ -246,8 +243,8 @@ func (h *Idler) patchIngress(ctx context.Context, opLog logr.Logger, namespace c ingressCopy := ingress.DeepCopy() mergePatch, _ := json.Marshal(map[string]interface{}{ "metadata": map[string]interface{}{ - "labels": map[string]string{ - "idling.amazee.io/idled": "true", + "labels": map[string]interface{}{ + "idling.lagoon.sh/idled": "true", }, "annotations": map[string]string{ // add the custom-http-errors annotation so that the unidler knows to handle this ingress @@ -271,8 +268,8 @@ func (h *Idler) patchIngress(ctx context.Context, opLog logr.Logger, namespace c namespaceCopy := namespace.DeepCopy() mergePatch, _ := json.Marshal(map[string]interface{}{ "metadata": map[string]interface{}{ - "labels": map[string]string{ - "idling.amazee.io/idled": "true", + "labels": map[string]interface{}{ + "idling.lagoon.sh/idled": "true", }, }, }) diff --git a/handlers/idler/service.go b/handlers/idler/service.go index b1b9837..f5740a5 100644 --- a/handlers/idler/service.go +++ b/handlers/idler/service.go @@ -17,11 +17,6 @@ import ( // +kubebuilder:rbac:groups=*,resources=ingresses,verbs=get;list;watch;update;patch // +kubebuilder:rbac:groups=*,resources=ingress/status,verbs=get;update;patch -type serviceIdler struct { - podInterval int - esInterval string -} - // ServiceIdler will run the Service idler process. func (h *Idler) ServiceIdler() { ctx := context.Background() @@ -36,7 +31,7 @@ func (h *Idler) ServiceIdler() { // @TODO: reintroduce this later on, since there are some cases where an environment is unidled where this // does not get changed currently // selector := generateSelector(idlerSelector{ - // Name: "idling.amazee.io/idled", + // Name: "idling.lagoon.sh/idled", // Operator: selection.NotEquals, // Values: []string{ // "true", @@ -66,7 +61,7 @@ func (h *Idler) ServiceIdler() { WithValues("project", namespace.ObjectMeta.Labels[h.Selectors.NamespaceSelectorsLabels.ProjectName]). WithValues("environment", namespace.ObjectMeta.Labels[h.Selectors.NamespaceSelectorsLabels.EnvironmentName]). WithValues("dry-run", h.DryRun) - envOpLog.Info(fmt.Sprintf("Checking namespace")) + envOpLog.Info("Checking namespace") h.KubernetesServiceIdler(ctx, envOpLog, namespace, namespace.ObjectMeta.Labels[h.Selectors.NamespaceSelectorsLabels.ProjectName], false, false) } else { if h.Debug { diff --git a/handlers/unidler/checks.go b/handlers/unidler/checks.go index 90490ff..09e9cf5 100644 --- a/handlers/unidler/checks.go +++ b/handlers/unidler/checks.go @@ -14,14 +14,13 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" "sigs.k8s.io/controller-runtime/pkg/client" - ctrlClient "sigs.k8s.io/controller-runtime/pkg/client" ) func (h *Unidler) checkForceScaled(ctx context.Context, ns string, opLog logr.Logger) bool { // get the deployments in the namespace if they have the `watch=true` label labelRequirements1, _ := labels.NewRequirement("idling.amazee.io/force-scaled", selection.Equals, []string{"true"}) - listOption := (&ctrlClient.ListOptions{}).ApplyOptions([]ctrlClient.ListOption{ - ctrlClient.InNamespace(ns), + listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ + client.InNamespace(ns), client.MatchingLabelsSelector{ Selector: labels.NewSelector().Add(*labelRequirements1), }, @@ -44,7 +43,7 @@ func (h *Unidler) hasRunningPod(ctx context.Context, namespace, deployment strin return false, err } var pods corev1.PodList - listOption := (&ctrlClient.ListOptions{}).ApplyOptions([]ctrlClient.ListOption{ + listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ client.MatchingLabelsSelector{ Selector: labels.SelectorFromSet(d.Spec.Selector.MatchLabels), }, @@ -61,8 +60,8 @@ func (h *Unidler) hasRunningPod(ctx context.Context, namespace, deployment strin func (h *Unidler) removeCodeFromIngress(ctx context.Context, ns string, opLog logr.Logger) { // get the ingresses in the namespace - listOption := (&ctrlClient.ListOptions{}).ApplyOptions([]ctrlClient.ListOption{ - ctrlClient.InNamespace(ns), + listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ + client.InNamespace(ns), }) ingresses := &networkv1.IngressList{} if err := h.Client.List(ctx, ingresses, listOption); err != nil { @@ -80,18 +79,18 @@ func (h *Unidler) removeCodeFromIngress(ctx context.Context, ns string, opLog lo if newVals == nil || *newVals != value { mergePatch, _ := json.Marshal(map[string]interface{}{ "metadata": map[string]interface{}{ - "labels": map[string]*string{ - "idling.amazee.io/idled": nil, + "labels": map[string]string{ + "idling.lagoon.sh/idled": "false", }, - "annotations": map[string]*string{ + "annotations": map[string]interface{}{ "nginx.ingress.kubernetes.io/custom-http-errors": newVals, - "idling.amazee.io/idled-at": nil, - "idling.amazee.io/idled": nil, + "idling.lagoon.sh/idled-at": nil, + "idling.lagoon.sh/idled": nil, }, }, }) patchIngress := ingress.DeepCopy() - if err := h.Client.Patch(ctx, patchIngress, ctrlClient.RawPatch(types.MergePatchType, mergePatch)); err != nil { + if err := h.Client.Patch(ctx, patchIngress, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { // log it but try and patch the rest of the ingressses anyway (some is better than none?) opLog.Info(fmt.Sprintf("Error patching custom-http-errors on ingress %s - %s", ingress.ObjectMeta.Name, ns)) } else { diff --git a/handlers/unidler/handler.go b/handlers/unidler/handler.go index c179910..8100433 100644 --- a/handlers/unidler/handler.go +++ b/handlers/unidler/handler.go @@ -22,7 +22,6 @@ func (h *Unidler) ingressHandler(path string) func(http.ResponseWriter, *http.Re ctx := context.Background() opLog := h.Log.WithValues("custom-default-backend", "request") start := time.Now() - ext := "html" // if debug is enabled, then set the headers in the response too if os.Getenv("DEBUG") == "true" { w.Header().Set(FormatHeader, r.Header.Get(FormatHeader)) @@ -40,14 +39,10 @@ func (h *Unidler) ingressHandler(path string) func(http.ResponseWriter, *http.Re format = "text/html" } - cext, err := mime.ExtensionsByType(format) + _, err := mime.ExtensionsByType(format) if err != nil { // log.Printf("unexpected error reading media type extension: %v. Using %v", err, ext) format = "text/html" - } else if len(cext) == 0 { - // log.Printf("couldn't get media type extension. Using %v", ext) - } else { - ext = cext[0] } w.Header().Set(ContentType, format) w.Header().Set(AergiaHeader, "true") @@ -78,7 +73,7 @@ func (h *Unidler) ingressHandler(path string) func(http.ResponseWriter, *http.Re Name: ingressName, }, ingress); err != nil { opLog.Info(fmt.Sprintf("Unable to get the ingress %s in %s", ingressName, ns)) - h.genericError(w, r, opLog, ext, format, path, "", 400) + h.genericError(w, r, opLog, format, path, "", 400) h.setMetrics(r, start) return } @@ -117,7 +112,7 @@ func (h *Unidler) ingressHandler(path string) func(http.ResponseWriter, *http.Re w.Header().Set("X-Aergia-Verification-Required", "true") } } - if h.Debug == true { + if h.Debug { opLog.Info(fmt.Sprintf("Serving custom error response for code %v and format %v from file %v", code, format, file)) } // then return the unidle template to the user @@ -140,25 +135,21 @@ func (h *Unidler) ingressHandler(path string) func(http.ResponseWriter, *http.Re // respond with forbidden w.Header().Set("X-Aergia-Denied", "true") blockedRequests.Inc() - h.genericError(w, r, opLog, ext, format, path, "", 403) + h.genericError(w, r, opLog, format, path, "", 403) } } else { w.Header().Set("X-Aergia-Denied", "true") w.Header().Set("X-Aergia-No-Namespace", "true") noNamespaceRequests.Inc() - h.genericError(w, r, opLog, ext, format, path, "", code) + h.genericError(w, r, opLog, format, path, "", code) } h.setMetrics(r, start) } } -func (h *Unidler) genericError(w http.ResponseWriter, r *http.Request, opLog logr.Logger, ext, format, path, verifier string, code int) { - // otherwise just handle the generic http responses here - if !strings.HasPrefix(ext, ".") { - ext = "." + ext - } +func (h *Unidler) genericError(w http.ResponseWriter, r *http.Request, opLog logr.Logger, format, path, verifier string, code int) { file := fmt.Sprintf("%v/error.html", path) - if h.Debug == true { + if h.Debug { opLog.Info(fmt.Sprintf("Serving custom error response for code %v and format %v from file %v", code, format, file)) } tmpl := template.Must(template.ParseFiles(file)) @@ -182,9 +173,9 @@ func (h *Unidler) genericError(w http.ResponseWriter, r *http.Request, opLog log // handle verifying the namespace name is signed by our secret func (h *Unidler) verifyRequest(r *http.Request, ns *corev1.Namespace) (string, bool) { if h.VerifiedUnidling { - if val, ok := ns.ObjectMeta.Annotations["idling.amazee.io/disable-request-verification"]; ok { + if val, ok := ns.ObjectMeta.Annotations["idling.lagoon.sh/disable-request-verification"]; ok { t, _ := strconv.ParseBool(val) - if t == true { + if t { return "", true } } diff --git a/handlers/unidler/metrics.go b/handlers/unidler/metrics.go index f78b094..238d612 100644 --- a/handlers/unidler/metrics.go +++ b/handlers/unidler/metrics.go @@ -11,7 +11,7 @@ import ( ) func (h *Unidler) setMetrics(r *http.Request, start time.Time) { - duration := time.Now().Sub(start).Seconds() + duration := time.Since(start).Seconds() proto := strconv.Itoa(r.ProtoMajor) proto = fmt.Sprintf("%s.%s", proto, strconv.Itoa(r.ProtoMinor)) diff --git a/handlers/unidler/restrictions.go b/handlers/unidler/restrictions.go index 8f68566..f5009ba 100644 --- a/handlers/unidler/restrictions.go +++ b/handlers/unidler/restrictions.go @@ -36,19 +36,19 @@ func checkIPList(allowList []string, xForwardedFor []string, trueClientIP string func (h *Unidler) checkAccess(nsannotations map[string]string, annotations map[string]string, userAgent, trueClientIP string, xForwardedFor []string) bool { // deal with ip allow/blocks first - blockedIP := checkIPAnnotations("idling.amazee.io/ip-block-list", trueClientIP, xForwardedFor, h.BlockedIPs, nsannotations, annotations) + blockedIP := checkIPAnnotations("idling.lagoon.sh/ip-block-list", trueClientIP, xForwardedFor, h.BlockedIPs, nsannotations, annotations) if blockedIP { return false } - allowedIP := checkIPAnnotations("idling.amazee.io/ip-allow-list", trueClientIP, xForwardedFor, h.AllowedIPs, nsannotations, annotations) + allowedIP := checkIPAnnotations("idling.lagoon.sh/ip-allow-list", trueClientIP, xForwardedFor, h.AllowedIPs, nsannotations, annotations) if allowedIP { return true } - blockedAgent := checkAgentAnnotations("idling.amazee.io/blocked-agents", userAgent, h.BlockedUserAgents, nsannotations, annotations) + blockedAgent := checkAgentAnnotations("idling.lagoon.sh/blocked-agents", userAgent, h.BlockedUserAgents, nsannotations, annotations) if blockedAgent { return false } - allowedAgent := checkAgentAnnotations("idling.amazee.io/allowed-agents", userAgent, h.AllowedUserAgents, nsannotations, annotations) + allowedAgent := checkAgentAnnotations("idling.lagoon.sh/allowed-agents", userAgent, h.AllowedUserAgents, nsannotations, annotations) if allowedAgent { return true } diff --git a/handlers/unidler/restrictions_test.go b/handlers/unidler/restrictions_test.go index a8cc841..e5360b7 100644 --- a/handlers/unidler/restrictions_test.go +++ b/handlers/unidler/restrictions_test.go @@ -165,7 +165,7 @@ func TestUnidler_checkAccess(t *testing.T) { name: "test3 - blocked agent annotation", args: args{ annotations: map[string]string{ - "idling.amazee.io/blocked-agents": "@(example).test.?$,@(internal).test.?$", + "idling.lagoon.sh/blocked-agents": "@(example).test.?$,@(internal).test.?$", }, userAgent: "This is a bot, complaints to: complain@example.test.", trueClientIP: "1.2.3.4", @@ -199,7 +199,7 @@ func TestUnidler_checkAccess(t *testing.T) { name: "test5 - blocked ip annotation", args: args{ annotations: map[string]string{ - "idling.amazee.io/ip-block-list": "1.2.3.4", + "idling.lagoon.sh/ip-block-list": "1.2.3.4", }, userAgent: "This is a bot, complaints to: complain@example.test.", trueClientIP: "1.2.3.4", @@ -233,7 +233,7 @@ func TestUnidler_checkAccess(t *testing.T) { name: "test7 - allowed ip annotation", args: args{ annotations: map[string]string{ - "idling.amazee.io/ip-allow-list": "1.2.3.4", + "idling.lagoon.sh/ip-allow-list": "1.2.3.4", }, userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 13_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36", trueClientIP: "1.2.3.4", @@ -269,7 +269,7 @@ func TestUnidler_checkAccess(t *testing.T) { name: "test9 - allowed agent annotation", args: args{ annotations: map[string]string{ - "idling.amazee.io/allowed-agents": "@(example).test.?$,@(internal).test.?$", + "idling.lagoon.sh/allowed-agents": "@(example).test.?$,@(internal).test.?$", }, userAgent: "This is not a bot, don't complaint to: complain@example.test.", trueClientIP: "1.2.3.4", @@ -308,8 +308,8 @@ func TestUnidler_checkAccess(t *testing.T) { name: "test11 - allowed agent blocked ip annotation", args: args{ annotations: map[string]string{ - "idling.amazee.io/allowed-agents": "@(example).test.?$,@(internal).test.?$", - "idling.amazee.io/ip-block-list": "1.2.3.4", + "idling.lagoon.sh/allowed-agents": "@(example).test.?$,@(internal).test.?$", + "idling.lagoon.sh/ip-block-list": "1.2.3.4", }, userAgent: "This is not a bot, don't complaint to: complain@example.test.", trueClientIP: "1.2.3.4", @@ -348,8 +348,8 @@ func TestUnidler_checkAccess(t *testing.T) { name: "test13 - allowed ip blocked agent annotation", args: args{ annotations: map[string]string{ - "idling.amazee.io/blocked-agents": "@(example).test.?$,@(internal).test.?$", - "idling.amazee.io/ip-allow-list": "1.2.3.4", + "idling.lagoon.sh/blocked-agents": "@(example).test.?$,@(internal).test.?$", + "idling.lagoon.sh/ip-allow-list": "1.2.3.4", }, userAgent: "This is not a bot, don't complaint to: complain@example.test.", trueClientIP: "1.2.3.4", @@ -367,8 +367,8 @@ func TestUnidler_checkAccess(t *testing.T) { name: "test15 - allowed ip blocked agent namespace annotation", args: args{ nsannotations: map[string]string{ - "idling.amazee.io/blocked-agents": "@(example).test.?$,@(internal).test.?$", - "idling.amazee.io/ip-allow-list": "1.2.3.4", + "idling.lagoon.sh/blocked-agents": "@(example).test.?$,@(internal).test.?$", + "idling.lagoon.sh/ip-allow-list": "1.2.3.4", }, userAgent: "This is not a bot, don't complaint to: complain@example.test.", trueClientIP: "1.2.3.4", diff --git a/handlers/unidler/unidler.go b/handlers/unidler/unidler.go index b8d7bae..f8a9800 100644 --- a/handlers/unidler/unidler.go +++ b/handlers/unidler/unidler.go @@ -19,7 +19,6 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/wait" "sigs.k8s.io/controller-runtime/pkg/client" - ctrlClient "sigs.k8s.io/controller-runtime/pkg/client" ) // +kubebuilder:rbac:groups=apps,resources=deployments,verbs=list;get;watch;patch;update @@ -34,7 +33,7 @@ const ( // Unidler is the client structure for http handlers. type Unidler struct { - Client ctrlClient.Client + Client client.Client Log logr.Logger RefreshInterval int UnidlerHTTPPort int @@ -125,15 +124,15 @@ func faviconHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set(AergiaHeader, "true") w.Header().Set("Content-Type", "image/x-icon") w.Header().Set("Cache-Control", "public, max-age=7776000") - fmt.Fprintln(w, fmt.Sprintf("%s\n", favicon)) + fmt.Fprintf(w, "%s\n", favicon) } func (h *Unidler) Unidle(ctx context.Context, namespace *corev1.Namespace, opLog logr.Logger) { defer h.Locks.Delete(namespace.Name) // get the deployments in the namespace if they have the `watch=true` label - labelRequirements1, _ := labels.NewRequirement("idling.amazee.io/watch", selection.Equals, []string{"true"}) - listOption := (&ctrlClient.ListOptions{}).ApplyOptions([]ctrlClient.ListOption{ - ctrlClient.InNamespace(namespace.Name), + labelRequirements1, _ := labels.NewRequirement("idling.lagoon.sh/watch", selection.Equals, []string{"true"}) + listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ + client.InNamespace(namespace.Name), client.MatchingLabelsSelector{ Selector: labels.NewSelector().Add(*labelRequirements1), }, @@ -145,14 +144,14 @@ func (h *Unidler) Unidle(ctx context.Context, namespace *corev1.Namespace, opLog } for _, deploy := range deployments.Items { // if the idled annotation is true - av, aok := deploy.ObjectMeta.Annotations["idling.amazee.io/idled"] - lv, lok := deploy.ObjectMeta.Labels["idling.amazee.io/idled"] + av, aok := deploy.ObjectMeta.Annotations["idling.lagoon.sh/idled"] + lv, lok := deploy.ObjectMeta.Labels["idling.lagoon.sh/idled"] if aok && av == "true" || lok && lv == "true" { opLog.Info(fmt.Sprintf("Deployment %s - Replicas %v - %s", deploy.ObjectMeta.Name, *deploy.Spec.Replicas, namespace.Name)) if *deploy.Spec.Replicas == 0 { // default to scaling to 1 replica newReplicas := 1 - if value, ok := deploy.ObjectMeta.Annotations["idling.amazee.io/unidle-replicas"]; ok { + if value, ok := deploy.ObjectMeta.Annotations["idling.lagoon.sh/unidle-replicas"]; ok { // but if the value of the annotation is greater than 0, use what is in the annotation instead unidleReplicas, err := strconv.Atoi(value) if err == nil { @@ -167,18 +166,18 @@ func (h *Unidler) Unidle(ctx context.Context, namespace *corev1.Namespace, opLog }, "metadata": map[string]interface{}{ "labels": map[string]*string{ - "idling.amazee.io/idled": nil, - "idling.amazee.io/force-idled": nil, - "idling.amazee.io/force-scaled": nil, + "idling.lagoon.sh/idled": nil, + "idling.lagoon.sh/force-idled": nil, + "idling.lagoon.sh/force-scaled": nil, }, "annotations": map[string]*string{ - "idling.amazee.io/idled-at": nil, - "idling.amazee.io/idled": nil, + "idling.lagoon.sh/idled-at": nil, + "idling.lagoon.sh/idled": nil, }, }, }) scaleDepConf := deploy.DeepCopy() - if err := h.Client.Patch(ctx, scaleDepConf, ctrlClient.RawPatch(types.MergePatchType, mergePatch)); err != nil { + if err := h.Client.Patch(ctx, scaleDepConf, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { // log it but try and scale the rest of the deployments anyway (some idled is better than none?) opLog.Info(fmt.Sprintf("Error scaling deployment %s - %s", deploy.ObjectMeta.Name, namespace.Name)) } else { @@ -200,7 +199,7 @@ func (h *Unidler) Unidle(ctx context.Context, namespace *corev1.Namespace, opLog mergePatch, _ := json.Marshal(map[string]interface{}{ "metadata": map[string]interface{}{ "labels": map[string]string{ - "idling.amazee.io/idled": "false", + "idling.lagoon.sh/idled": "false", }, }, }) diff --git a/helm-update.sh b/helm-update.sh deleted file mode 100755 index 11a269c..0000000 --- a/helm-update.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash - -# ./helm-update.sh index -# create new index for the chart - -# ./helm-update.sh template -# process the chart to a template - -# ./helm-update.sh delete -# delete the chart from kubernetes - -# ./helm-update.sh install -# install the chart into kubernetes - -# ./helm-update.sh install-tgz -# install the chart from one of the tgz files present locally into kubernetes - -case $1 in - index) - pushd charts - helm package aergia - helm repo index . - popd - ;; - template) - helm template charts/aergia -f charts/aergia/values.yaml - ;; - delete) - helm delete -n aergia aergia - ;; - install) - helm repo add aergia https://raw.githubusercontent.com/amazeeio/unidler/main/charts - helm upgrade --install -n aergia aergia aergia/aergia - ;; - install-tgz) - options=($(ls charts | grep tgz)) - if [ ${#options[@]} -ne 0 ]; then - select chart in "${options[@]}"; - do - case $chart in - "$QUIT") - echo "Unknown option, exiting." - break - ;; - *) - break - ;; - esac - done - if [ "$chart" != "" ]; then - helm upgrade --install --create-namespace -n aergia aergia charts/$chart - fi - else - echo "No chart files, exiting." - fi - ;; - *) - echo "nothing" - ;; -esac - diff --git a/main.go b/main.go index 7888641..a7ffa25 100644 --- a/main.go +++ b/main.go @@ -22,13 +22,13 @@ import ( "os" "time" - "github.com/amazeeio/aergia-controller/controllers" - "github.com/amazeeio/aergia-controller/handlers/idler" - "github.com/amazeeio/aergia-controller/handlers/metrics" - "github.com/amazeeio/aergia-controller/handlers/unidler" - u "github.com/amazeeio/aergia-controller/handlers/unidler" prometheusapi "github.com/prometheus/client_golang/api" "github.com/prometheus/client_golang/prometheus" + "github.com/uselagoon/aergia-controller/controllers" + "github.com/uselagoon/aergia-controller/handlers/idler" + "github.com/uselagoon/aergia-controller/handlers/metrics" + "github.com/uselagoon/aergia-controller/handlers/unidler" + u "github.com/uselagoon/aergia-controller/handlers/unidler" variables "github.com/uselagoon/machinery/utils/variables" "gopkg.in/robfig/cron.v2" "gopkg.in/yaml.v2" diff --git a/test-resources/aergia-backend.yaml b/test-resources/aergia-backend.yaml index d826328..a07a8cc 100644 --- a/test-resources/aergia-backend.yaml +++ b/test-resources/aergia-backend.yaml @@ -258,7 +258,7 @@ spec: name: backend command: - /manager - image: amazeeiolocal/aergia:test-tag + image: uselagoonlocal/aergia:test-tag name: manager resources: limits: diff --git a/test-resources/example-nginx.yaml b/test-resources/example-nginx.yaml index 7352c9e..823fbcf 100644 --- a/test-resources/example-nginx.yaml +++ b/test-resources/example-nginx.yaml @@ -32,14 +32,14 @@ metadata: name: example-nginx namespace: example-nginx labels: - idling.amazee.io/watch: 'true' - idling.amazee.io/idled: 'true' + idling.lagoon.sh/watch: 'true' + idling.lagoon.sh/idled: 'true' lagoon.sh/service: "nginx" lagoon.sh/project: example lagoon.sh/environment: "nginx" lagoon.sh/environmentType: "development" annotations: - idling.amazee.io/unidle-replicas: '3' + idling.lagoon.sh/unidle-replicas: '3' spec: replicas: 0 selector: