From 968dafea4f25dc93d749ec896d9bf7987c08f9fa Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 4 Jun 2021 09:43:38 +1000 Subject: [PATCH 01/35] add build cancellation functionality to prevent multiple builds piling up, and begin splitting out functions for qos handling --- controller-test.sh | 2 +- controllers/helpers.go | 35 + controllers/lagoonbuild_controller.go | 971 +-------------------- controllers/lagoonbuild_helpers.go | 855 ++++++++++++++++++ controllers/lagoonbuild_qoshandler.go | 24 + controllers/lagoonbuild_standardhandler.go | 71 ++ controllers/lagoonmonitor_controller.go | 23 +- main.go | 17 + 8 files changed, 1045 insertions(+), 953 deletions(-) create mode 100644 controllers/lagoonbuild_helpers.go create mode 100644 controllers/lagoonbuild_qoshandler.go create mode 100644 controllers/lagoonbuild_standardhandler.go diff --git a/controller-test.sh b/controller-test.sh index 79ec2947..32d9010b 100755 --- a/controller-test.sh +++ b/controller-test.sh @@ -291,7 +291,7 @@ else exit 1 fi done -echo "==> Pod cleanup output (should only be lagoon-build-8m5zypx)" +echo "==> Pod cleanup output (should only be 1 lagoon-build pod)" POD_CLEANUP_OUTPUT=$(kubectl -n drupal-example-install get pods | grep "lagoon-build") echo "${POD_CLEANUP_OUTPUT}" POD_CLEANUP_COUNT=$(echo "${POD_CLEANUP_OUTPUT}" | wc -l | tr -d " ") diff --git a/controllers/helpers.go b/controllers/helpers.go index 6e1d0e98..4195b176 100644 --- a/controllers/helpers.go +++ b/controllers/helpers.go @@ -1,18 +1,22 @@ package controllers import ( + "context" "crypto/sha1" "crypto/sha256" "encoding/base32" "fmt" "math/rand" "regexp" + "sort" "strconv" "strings" "time" lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" + "github.com/go-logr/logr" apierrors "k8s.io/apimachinery/pkg/api/errors" + "sigs.k8s.io/controller-runtime/pkg/client" ) const ( @@ -172,3 +176,34 @@ func variableExists(vars *[]LagoonEnvironmentVariable, name, value string) bool } return exists } + +func cancelExtraBuilds(ctx context.Context, r client.Client, opLog logr.Logger, pendingBuilds *lagoonv1alpha1.LagoonBuildList, ns string, status string) error { + listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ + client.InNamespace(ns), + client.MatchingLabels(map[string]string{"lagoon.sh/buildStatus": "Pending"}), + }) + if err := r.List(ctx, pendingBuilds, listOption); err != nil { + return fmt.Errorf("Unable to list builds in the namespace, there may be none or something went wrong: %v", err) + } + opLog.Info(fmt.Sprintf("There are %v Pending builds", len(pendingBuilds.Items))) + // if we have any pending builds, then grab the latest one and make it running + // if there are any other pending builds, cancel them so only the latest one runs + sort.Slice(pendingBuilds.Items, func(i, j int) bool { + return pendingBuilds.Items[i].ObjectMeta.CreationTimestamp.After(pendingBuilds.Items[j].ObjectMeta.CreationTimestamp.Time) + }) + if len(pendingBuilds.Items) > 0 { + for idx, pBuild := range pendingBuilds.Items { + pendingBuild := pBuild.DeepCopy() + if idx == 0 { + pendingBuild.Labels["lagoon.sh/buildStatus"] = status + } else { + // cancel any other pending builds + pendingBuild.Labels["lagoon.sh/buildStatus"] = "Cancelled" + } + if err := r.Update(ctx, pendingBuild); err != nil { + return err + } + } + } + return nil +} diff --git a/controllers/lagoonbuild_controller.go b/controllers/lagoonbuild_controller.go index a97270bb..29969779 100644 --- a/controllers/lagoonbuild_controller.go +++ b/controllers/lagoonbuild_controller.go @@ -16,20 +16,13 @@ limitations under the License. package controllers import ( - "bytes" "context" "encoding/json" "fmt" - "regexp" - "sort" - "strconv" - "strings" - "time" "github.com/go-logr/logr" corev1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" @@ -37,11 +30,7 @@ import ( lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" "github.com/amazeeio/lagoon-kbd/handlers" - - "gopkg.in/matryer/try.v1" - // Openshift - projectv1 "github.com/openshift/api/project/v1" ) // LagoonBuildReconciler reconciles a LagoonBuild object @@ -76,6 +65,8 @@ type LagoonBuildReconciler struct { LFFBackupWeeklyRandom bool LFFHarborEnabled bool Harbor Harbor + LFFQoSEnabled bool + BuildQoS BuildQoS } // +kubebuilder:rbac:groups=lagoon.amazee.io,resources=lagoonbuilds,verbs=get;list;watch;create;update;patch;delete @@ -99,619 +90,11 @@ func (r *LagoonBuildReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) // examine DeletionTimestamp to determine if object is under deletion if lagoonBuild.ObjectMeta.DeletionTimestamp.IsZero() { - // check if we get a lagoonbuild that hasn't got any buildstatus - // this means it was created by the message queue handler - // so we should do the steps required for a lagoon build and then copy the build - // into the created namespace - if _, ok := lagoonBuild.ObjectMeta.Labels["lagoon.sh/buildStatus"]; !ok { - // Namesapce creation - namespace := &corev1.Namespace{} - opLog.Info(fmt.Sprintf("Checking Namespace exists for: %s", lagoonBuild.ObjectMeta.Name)) - err := r.getOrCreateNamespace(ctx, namespace, lagoonBuild.Spec) - if err != nil { - return ctrl.Result{}, err - } - // create the `lagoon-deployer` ServiceAccount - opLog.Info(fmt.Sprintf("Checking `lagoon-deployer` ServiceAccount exists: %s", lagoonBuild.ObjectMeta.Name)) - serviceAccount := &corev1.ServiceAccount{} - err = r.getOrCreateServiceAccount(ctx, serviceAccount, namespace.ObjectMeta.Name) - if err != nil { - return ctrl.Result{}, err - } - // ServiceAccount RoleBinding creation - opLog.Info(fmt.Sprintf("Checking `lagoon-deployer-admin` RoleBinding exists: %s", lagoonBuild.ObjectMeta.Name)) - saRoleBinding := &rbacv1.RoleBinding{} - err = r.getOrCreateSARoleBinding(ctx, saRoleBinding, namespace.ObjectMeta.Name) - if err != nil { - return ctrl.Result{}, err - } - - if r.IsOpenshift && lagoonBuild.Spec.Build.Type == "promote" { - err := r.getOrCreatePromoteSARoleBinding(ctx, lagoonBuild.Spec.Promote.SourceProject, namespace.ObjectMeta.Name) - if err != nil { - return ctrl.Result{}, err - } - } - - // copy the build resource into a new resource and set the status to pending - // create the new resource and the controller will handle it via queue - opLog.Info(fmt.Sprintf("Creating LagoonBuild in Pending status: %s", lagoonBuild.ObjectMeta.Name)) - err = r.getOrCreateBuildResource(ctx, &lagoonBuild, namespace.ObjectMeta.Name) - if err != nil { - return ctrl.Result{}, err - } - // if everything is all good controller will handle the new build resource that gets created as it will have - // the `lagoon.sh/buildStatus = Pending` now - // so end this reconcile process - return ctrl.Result{}, nil - } - // if we do have a `lagoon.sh/buildStatus` set, then process as normal - runningBuilds := &lagoonv1alpha1.LagoonBuildList{} - listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ - client.InNamespace(req.Namespace), - client.MatchingLabels(map[string]string{ - "lagoon.sh/buildStatus": "Running", - "lagoon.sh/controller": r.ControllerNamespace, - }), - }) - // list any builds that are running - if err := r.List(ctx, runningBuilds, listOption); err != nil { - return ctrl.Result{}, fmt.Errorf("Unable to list builds in the namespace, there may be none or something went wrong: %v", err) - } - for _, runningBuild := range runningBuilds.Items { - // if the running build is the one from this request then process it - if lagoonBuild.ObjectMeta.Name == runningBuild.ObjectMeta.Name { - // we run these steps again just to be sure that it gets updated/created if it hasn't already - opLog.Info(fmt.Sprintf("Starting work on build: %s", lagoonBuild.ObjectMeta.Name)) - // create the lagoon-sshkey secret - sshKey := &corev1.Secret{} - opLog.Info(fmt.Sprintf("Checking `lagoon-sshkey` Secret exists: %s", lagoonBuild.ObjectMeta.Name)) - err := r.getCreateOrUpdateSSHKeySecret(ctx, sshKey, lagoonBuild.Spec, lagoonBuild.ObjectMeta.Namespace) - if err != nil { - return ctrl.Result{}, err - } - - // create the `lagoon-deployer` ServiceAccount - opLog.Info(fmt.Sprintf("Checking `lagoon-deployer` ServiceAccount exists: %s", lagoonBuild.ObjectMeta.Name)) - serviceAccount := &corev1.ServiceAccount{} - err = r.getOrCreateServiceAccount(ctx, serviceAccount, lagoonBuild.ObjectMeta.Namespace) - if err != nil { - return ctrl.Result{}, err - } - - // ServiceAccount RoleBinding creation - opLog.Info(fmt.Sprintf("Checking `lagoon-deployer-admin` RoleBinding exists: %s", lagoonBuild.ObjectMeta.Name)) - saRoleBinding := &rbacv1.RoleBinding{} - err = r.getOrCreateSARoleBinding(ctx, saRoleBinding, lagoonBuild.ObjectMeta.Namespace) - if err != nil { - return ctrl.Result{}, err - } - - if r.IsOpenshift && lagoonBuild.Spec.Build.Type == "promote" { - err := r.getOrCreatePromoteSARoleBinding(ctx, lagoonBuild.Spec.Promote.SourceProject, lagoonBuild.ObjectMeta.Namespace) - if err != nil { - return ctrl.Result{}, err - } - } - - opLog.Info(fmt.Sprintf("Checking `lagoon-deployer` Token exists: %s", lagoonBuild.ObjectMeta.Name)) - var serviceaccountTokenSecret string - for _, secret := range serviceAccount.Secrets { - match, _ := regexp.MatchString("^lagoon-deployer-token", secret.Name) - if match { - serviceaccountTokenSecret = secret.Name - break - } - } - if serviceaccountTokenSecret == "" { - return ctrl.Result{}, fmt.Errorf("Could not find token secret for ServiceAccount lagoon-deployer") - } - - // openshift uses a builder service account to be able to push images to the openshift registry - // lets load this in exactly the same way an openshift build would - var builderServiceaccountTokenSecret string - if r.IsOpenshift { - builderAccount := &corev1.ServiceAccount{} - err := r.Get(ctx, types.NamespacedName{ - Namespace: lagoonBuild.ObjectMeta.Namespace, - Name: "builder", - }, builderAccount) - if err != nil { - return ctrl.Result{}, fmt.Errorf("Could not find ServiceAccount builder") - } - opLog.Info(fmt.Sprintf("Checking `builder` Token exists: %s", lagoonBuild.ObjectMeta.Name)) - for _, secret := range builderAccount.Secrets { - match, _ := regexp.MatchString("^builder-token", secret.Name) - if match { - builderServiceaccountTokenSecret = secret.Name - break - } - } - if builderServiceaccountTokenSecret == "" { - return ctrl.Result{}, fmt.Errorf("Could not find token secret for ServiceAccount builder") - } - } - - // create the Pod that will do the work - podEnvs := []corev1.EnvVar{ - { - Name: "SOURCE_REPOSITORY", - Value: lagoonBuild.Spec.Project.GitURL, - }, - { - Name: "GIT_REF", - Value: lagoonBuild.Spec.GitReference, - }, - { - Name: "SUBFOLDER", - Value: lagoonBuild.Spec.Project.SubFolder, - }, - { - Name: "BRANCH", - Value: lagoonBuild.Spec.Branch.Name, - }, - { - Name: "PROJECT", - Value: lagoonBuild.Spec.Project.Name, - }, - { - Name: "ENVIRONMENT_TYPE", - Value: lagoonBuild.Spec.Project.EnvironmentType, - }, - { - Name: "ACTIVE_ENVIRONMENT", - Value: lagoonBuild.Spec.Project.ProductionEnvironment, - }, - { - Name: "STANDBY_ENVIRONMENT", - Value: lagoonBuild.Spec.Project.StandbyEnvironment, - }, - { - Name: "PROJECT_SECRET", - Value: lagoonBuild.Spec.Project.ProjectSecret, - }, - { - Name: "MONITORING_ALERTCONTACT", - Value: lagoonBuild.Spec.Project.Monitoring.Contact, - }, - { - Name: "MONTHLY_BACKUP_DEFAULT_RETENTION", - Value: strconv.Itoa(r.BackupDefaultMonthlyRetention), - }, - { - Name: "WEEKLY_BACKUP_DEFAULT_RETENTION", - Value: strconv.Itoa(r.BackupDefaultWeeklyRetention), - }, - { - Name: "DAILY_BACKUP_DEFAULT_RETENTION", - Value: strconv.Itoa(r.BackupDefaultDailyRetention), - }, - { - Name: "K8UP_WEEKLY_RANDOM_FEATURE_FLAG", - Value: strconv.FormatBool(r.LFFBackupWeeklyRandom), - }, - } - if r.IsOpenshift { - // openshift builds have different names for some things, and also additional values to add - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "TYPE", - Value: lagoonBuild.Spec.Build.Type, - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "SAFE_BRANCH", - Value: lagoonBuild.Spec.Project.Environment, - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "SAFE_PROJECT", - Value: makeSafe(lagoonBuild.Spec.Project.Name), - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "OPENSHIFT_NAME", - Value: lagoonBuild.Spec.Project.DeployTarget, - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "ROUTER_URL", - Value: strings.ToLower( - strings.Replace( - strings.Replace( - lagoonBuild.Spec.Project.RouterPattern, - "${branch}", - lagoonBuild.Spec.Project.Environment, - -1, - ), - "${project}", - lagoonBuild.Spec.Project.Name, - -1, - ), - ), - }) - } else { - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "BUILD_TYPE", - Value: lagoonBuild.Spec.Build.Type, - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "ENVIRONMENT", - Value: lagoonBuild.Spec.Project.Environment, - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "KUBERNETES", - Value: lagoonBuild.Spec.Project.DeployTarget, - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "REGISTRY", - Value: lagoonBuild.Spec.Project.Registry, - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "ROUTER_URL", - Value: strings.ToLower( - strings.Replace( - strings.Replace( - lagoonBuild.Spec.Project.RouterPattern, - "${environment}", - lagoonBuild.Spec.Project.Environment, - -1, - ), - "${project}", - lagoonBuild.Spec.Project.Name, - -1, - ), - ), - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "SHORT_ROUTER_URL", - Value: strings.ToLower( - strings.Replace( - strings.Replace( - lagoonBuild.Spec.Project.RouterPattern, - "${environment}", - shortName(lagoonBuild.Spec.Project.Environment), - -1, - ), - "${project}", - shortName(lagoonBuild.Spec.Project.Name), - -1, - ), - ), - }) - } - if lagoonBuild.Spec.Build.CI != "" { - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "CI", - Value: lagoonBuild.Spec.Build.CI, - }) - } - if lagoonBuild.Spec.Build.Type == "pullrequest" { - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "PR_HEAD_BRANCH", - Value: lagoonBuild.Spec.Pullrequest.HeadBranch, - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "PR_HEAD_SHA", - Value: lagoonBuild.Spec.Pullrequest.HeadSha, - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "PR_BASE_BRANCH", - Value: lagoonBuild.Spec.Pullrequest.BaseBranch, - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "PR_BASE_SHA", - Value: lagoonBuild.Spec.Pullrequest.BaseSha, - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "PR_TITLE", - Value: lagoonBuild.Spec.Pullrequest.Title, - }) - if !r.IsOpenshift { - // we don't use PR_NUMBER in openshift builds - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "PR_NUMBER", - Value: string(lagoonBuild.Spec.Pullrequest.Number), - }) - } - } - if lagoonBuild.Spec.Build.Type == "promote" { - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "PROMOTION_SOURCE_ENVIRONMENT", - Value: lagoonBuild.Spec.Promote.SourceEnvironment, - }) - if r.IsOpenshift { - // openshift does promotions differently - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "PROMOTION_SOURCE_OPENSHIFT_PROJECT", - Value: lagoonBuild.Spec.Promote.SourceProject, - }) - } - } - // if local/regional harbor is enabled, and this is not an openshift 3 cluster - if r.LFFHarborEnabled && !r.IsOpenshift { - // unmarshal the project variables - lagoonProjectVariables := &[]LagoonEnvironmentVariable{} - lagoonEnvironmentVariables := &[]LagoonEnvironmentVariable{} - json.Unmarshal(lagoonBuild.Spec.Project.Variables.Project, lagoonProjectVariables) - json.Unmarshal(lagoonBuild.Spec.Project.Variables.Environment, lagoonEnvironmentVariables) - // check if INTERNAL_REGISTRY_SOURCE_LAGOON is defined, and if it isn't true - // if this value is true, then we want to use what is provided by Lagoon - // if it is false, or not set, then we use what is provided by this controller - // this allows us to make it so a specific environment or the project entirely - // can still use whats provided by lagoon - if !variableExists(lagoonProjectVariables, "INTERNAL_REGISTRY_SOURCE_LAGOON", "true") || - !variableExists(lagoonEnvironmentVariables, "INTERNAL_REGISTRY_SOURCE_LAGOON", "true") { - // source the robot credential, and inject it into the lagoon project variables - // this will overwrite what is provided by lagoon (if lagoon has provided them) - // or it will add them. - robotCredential := &corev1.Secret{} - if err = r.Get(ctx, types.NamespacedName{ - Namespace: lagoonBuild.ObjectMeta.Namespace, - Name: "lagoon-internal-registry-secret", - }, robotCredential); err != nil { - return ctrl.Result{}, fmt.Errorf("Could not find Harbor RobotAccount credential") - } - auths := Auths{} - if secretData, ok := robotCredential.Data[".dockerconfigjson"]; ok { - if err := json.Unmarshal(secretData, &auths); err != nil { - return ctrl.Result{}, fmt.Errorf("Could not unmarshal Harbor RobotAccount credential") - } - if len(auths.Registries) == 1 { - for registry, creds := range auths.Registries { - replaceOrAddVariable(lagoonProjectVariables, "INTERNAL_REGISTRY_URL", registry, "internal_container_registry") - replaceOrAddVariable(lagoonProjectVariables, "INTERNAL_REGISTRY_USERNAME", creds.Username, "internal_container_registry") - replaceOrAddVariable(lagoonProjectVariables, "INTERNAL_REGISTRY_PASSWORD", creds.Password, "internal_container_registry") - } - } - } - // marshal any changes into the project spec on the fly, don't save the spec though - // these values are being overwritten and injected directly into the build pod to be consumed - // by the build pod image - lagoonBuild.Spec.Project.Variables.Project, _ = json.Marshal(lagoonProjectVariables) - } - } - if lagoonBuild.Spec.Project.Variables.Project != nil { - // if this is 2 bytes long, then it means its just an empty json array - // we only want to add it if it is more than 2 bytes - if len(lagoonBuild.Spec.Project.Variables.Project) > 2 { - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "LAGOON_PROJECT_VARIABLES", - Value: string(lagoonBuild.Spec.Project.Variables.Project), - }) - } - } - if lagoonBuild.Spec.Project.Variables.Environment != nil { - // if this is 2 bytes long, then it means its just an empty json array - // we only want to add it if it is more than 2 bytes - if len(lagoonBuild.Spec.Project.Variables.Environment) > 2 { - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "LAGOON_ENVIRONMENT_VARIABLES", - Value: string(lagoonBuild.Spec.Project.Variables.Environment), - }) - } - } - if lagoonBuild.Spec.Project.Monitoring.StatuspageID != "" { - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "MONITORING_STATUSPAGEID", - Value: lagoonBuild.Spec.Project.Monitoring.StatuspageID, - }) - } - // if the fastly watch status is set on the controller, inject the fastly service ID into the build pod to be consumed - // by the build-depoy-dind image - if r.FastlyWatchStatus { - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "LAGOON_FASTLY_NOCACHE_SERVICE_ID", - Value: r.FastlyServiceID, - }) - } - // Set any defined Lagoon feature flags in the build environment. - if r.LFFForceRootlessWorkload != "" { - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "LAGOON_FEATURE_FLAG_FORCE_ROOTLESS_WORKLOAD", - Value: r.LFFForceRootlessWorkload, - }) - } - if r.LFFDefaultRootlessWorkload != "" { - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "LAGOON_FEATURE_FLAG_DEFAULT_ROOTLESS_WORKLOAD", - Value: r.LFFDefaultRootlessWorkload, - }) - } - if r.LFFForceIsolationNetworkPolicy != "" { - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "LAGOON_FEATURE_FLAG_FORCE_ISOLATION_NETWORK_POLICY", - Value: r.LFFForceIsolationNetworkPolicy, - }) - } - if r.LFFDefaultIsolationNetworkPolicy != "" { - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "LAGOON_FEATURE_FLAG_DEFAULT_ISOLATION_NETWORK_POLICY", - Value: r.LFFDefaultIsolationNetworkPolicy, - }) - } - // Use the build image in the controller definition - buildImage := r.BuildImage - if lagoonBuild.Spec.Build.Image != "" { - // otherwise if the build spec contains an image definition, use it instead. - buildImage = lagoonBuild.Spec.Build.Image - } - newPod := &corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: lagoonBuild.ObjectMeta.Name, - Namespace: lagoonBuild.ObjectMeta.Namespace, - Labels: map[string]string{ - "lagoon.sh/jobType": "build", - "lagoon.sh/buildName": lagoonBuild.ObjectMeta.Name, - "lagoon.sh/controller": r.ControllerNamespace, - "lagoon.sh/buildRemoteID": string(lagoonBuild.ObjectMeta.UID), - }, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: fmt.Sprintf("%v", lagoonv1alpha1.GroupVersion), - Kind: "LagoonBuild", - Name: lagoonBuild.ObjectMeta.Name, - UID: lagoonBuild.UID, - }, - }, - }, - Spec: corev1.PodSpec{ - RestartPolicy: "Never", - Volumes: []corev1.Volume{ - { - Name: serviceaccountTokenSecret, - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: serviceaccountTokenSecret, - DefaultMode: intPtr(420), - }, - }, - }, - { - Name: "lagoon-sshkey", - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: "lagoon-sshkey", - DefaultMode: intPtr(420), - }, - }, - }, - }, - Tolerations: []corev1.Toleration{ - { - Key: "lagoon/build", - Effect: "NoSchedule", - Operator: "Exists", - }, - { - Key: "lagoon/build", - Effect: "PreferNoSchedule", - Operator: "Exists", - }, - { - Key: "lagoon.sh/build", - Effect: "NoSchedule", - Operator: "Exists", - }, - { - Key: "lagoon.sh/build", - Effect: "PreferNoSchedule", - Operator: "Exists", - }, - }, - Containers: []corev1.Container{ - { - Name: "lagoon-build", - Image: buildImage, - ImagePullPolicy: "Always", - Env: podEnvs, - VolumeMounts: []corev1.VolumeMount{ - { - Name: serviceaccountTokenSecret, - ReadOnly: true, - MountPath: "/var/run/secrets/lagoon/deployer", - }, - { - Name: "lagoon-sshkey", - ReadOnly: true, - MountPath: "/var/run/secrets/lagoon/ssh", - }, - }, - }, - }, - }, - } - - // set the pod security context, if defined to a non-default value - if r.BuildPodRunAsUser != 0 || r.BuildPodRunAsGroup != 0 || - r.BuildPodFSGroup != 0 { - newPod.Spec.SecurityContext = &corev1.PodSecurityContext{ - RunAsUser: &r.BuildPodRunAsUser, - RunAsGroup: &r.BuildPodRunAsGroup, - FSGroup: &r.BuildPodFSGroup, - } - } - - // openshift uses a builder service account to be able to push images to the openshift registry - // load that into the podspec here - if r.IsOpenshift { - newPod.Spec.ServiceAccountName = "builder" - builderToken := corev1.VolumeMount{ - Name: builderServiceaccountTokenSecret, - ReadOnly: true, - MountPath: "/var/run/secrets/kubernetes.io/serviceaccount", - } - builderVolume := corev1.Volume{ - Name: builderServiceaccountTokenSecret, - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: builderServiceaccountTokenSecret, - DefaultMode: intPtr(420), - }, - }, - } - newPod.Spec.Volumes = append(newPod.Spec.Volumes, builderVolume) - newPod.Spec.Containers[0].VolumeMounts = append(newPod.Spec.Containers[0].VolumeMounts, builderToken) - } - opLog.Info(fmt.Sprintf("Checking build pod for: %s", lagoonBuild.ObjectMeta.Name)) - // once the pod spec has been defined, check if it isn't already created - err = r.Get(ctx, types.NamespacedName{ - Namespace: lagoonBuild.ObjectMeta.Namespace, - Name: newPod.ObjectMeta.Name, - }, newPod) - if err != nil { - // if it doesn't exist, then create the build pod - opLog.Info(fmt.Sprintf("Creating build pod for: %s", lagoonBuild.ObjectMeta.Name)) - if err := r.Create(ctx, newPod); err != nil { - opLog.Error(err, fmt.Sprintf("Unable to create build pod")) - // log the error and just exit, don't continue to try and do anything - // @TODO: should update the build to failed - return ctrl.Result{}, nil - } - // then break out of the build - break - } else { - opLog.Info(fmt.Sprintf("Build pod already running for: %s", lagoonBuild.ObjectMeta.Name)) - } - } // end check if running build is current LagoonBuild - } // end loop for running builds - - // if there are no running builds, check if there are any pending builds - if len(runningBuilds.Items) == 0 { - pendingBuilds := &lagoonv1alpha1.LagoonBuildList{} - listOption = (&client.ListOptions{}).ApplyOptions([]client.ListOption{ - client.InNamespace(req.Namespace), - client.MatchingLabels(map[string]string{ - "lagoon.sh/buildStatus": "Pending", - "lagoon.sh/controller": r.ControllerNamespace, - }), - }) - if err := r.List(ctx, pendingBuilds, listOption); err != nil { - return ctrl.Result{}, fmt.Errorf("Unable to list builds in the namespace, there may be none or something went wrong: %v", err) - } - // sort the pending builds by creation timestamp - sort.Slice(pendingBuilds.Items, func(i, j int) bool { - return pendingBuilds.Items[i].ObjectMeta.CreationTimestamp.Before(&pendingBuilds.Items[j].ObjectMeta.CreationTimestamp) - }) - if len(pendingBuilds.Items) > 0 { - pendingBuild := pendingBuilds.Items[0].DeepCopy() - pendingBuild.Labels["lagoon.sh/buildStatus"] = "Running" - if err := r.Update(ctx, pendingBuild); err != nil { - return ctrl.Result{}, err - } - } else { - opLog.Info(fmt.Sprintf("No pending builds")) - } - } - // The object is not being deleted, so if it does not have our finalizer, - // then lets add the finalizer and update the object. This is equivalent - // registering our finalizer. - if !containsString(lagoonBuild.ObjectMeta.Finalizers, finalizerName) { - lagoonBuild.ObjectMeta.Finalizers = append(lagoonBuild.ObjectMeta.Finalizers, finalizerName) - // use patches to avoid update errors - mergePatch, _ := json.Marshal(map[string]interface{}{ - "metadata": map[string]interface{}{ - "finalizers": lagoonBuild.ObjectMeta.Finalizers, - }, - }) - if err := r.Patch(ctx, &lagoonBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { - return ctrl.Result{}, err - } + if r.LFFQoSEnabled { + // handle QoS builds here + return r.qosBuildProcessor(ctx, opLog, lagoonBuild, req) + } else { + return r.standardBuildProcessor(ctx, opLog, lagoonBuild, req) } } else { // The object is being deleted @@ -757,241 +140,52 @@ func (r *LagoonBuildReconciler) SetupWithManager(mgr ctrl.Manager) error { Complete(r) } -// updateBuildStatusCondition is used to patch the lagoon build with the status conditions for the build, plus any logs -func (r *LagoonBuildReconciler) updateBuildStatusCondition(ctx context.Context, - lagoonBuild *lagoonv1alpha1.LagoonBuild, - condition lagoonv1alpha1.LagoonConditions, - log []byte, -) error { - // set the transition time - condition.LastTransitionTime = time.Now().UTC().Format(time.RFC3339) - if !jobContainsStatus(lagoonBuild.Status.Conditions, condition) { - lagoonBuild.Status.Conditions = append(lagoonBuild.Status.Conditions, condition) - mergePatch, _ := json.Marshal(map[string]interface{}{ - "status": map[string]interface{}{ - "conditions": lagoonBuild.Status.Conditions, - "log": log, - }, - }) - if err := r.Patch(ctx, lagoonBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { - return fmt.Errorf("Unable to update status condition: %v", err) - } - } - return nil -} +func (r *LagoonBuildReconciler) createNamespaceBuild(ctx context.Context, + opLog logr.Logger, + lagoonBuild lagoonv1alpha1.LagoonBuild) (ctrl.Result, error) { -// getOrCreateServiceAccount will create the lagoon-deployer service account if it doesn't exist. -func (r *LagoonBuildReconciler) getOrCreateServiceAccount(ctx context.Context, serviceAccount *corev1.ServiceAccount, ns string) error { - serviceAccount.ObjectMeta = metav1.ObjectMeta{ - Name: "lagoon-deployer", - Namespace: ns, - } - err := r.Get(ctx, types.NamespacedName{ - Namespace: ns, - Name: "lagoon-deployer", - }, serviceAccount) + namespace := &corev1.Namespace{} + opLog.Info(fmt.Sprintf("Checking Namespace exists for: %s", lagoonBuild.ObjectMeta.Name)) + err := r.getOrCreateNamespace(ctx, namespace, lagoonBuild.Spec) if err != nil { - if err := r.Create(ctx, serviceAccount); err != nil { - return err - } - } - return nil -} - -// getOrCreateSARoleBinding will create the rolebinding for the lagoon-deployer if it doesn't exist. -func (r *LagoonBuildReconciler) getOrCreateSARoleBinding(ctx context.Context, saRoleBinding *rbacv1.RoleBinding, ns string) error { - saRoleBinding.ObjectMeta = metav1.ObjectMeta{ - Name: "lagoon-deployer-admin", - Namespace: ns, + return ctrl.Result{}, err } - saRoleBinding.RoleRef = rbacv1.RoleRef{ - Name: "admin", - Kind: "ClusterRole", - APIGroup: "rbac.authorization.k8s.io", - } - saRoleBinding.Subjects = []rbacv1.Subject{ - { - Name: "lagoon-deployer", - Kind: "ServiceAccount", - Namespace: ns, - }, - } - err := r.Get(ctx, types.NamespacedName{ - Namespace: ns, - Name: "lagoon-deployer-admin", - }, saRoleBinding) + // create the `lagoon-deployer` ServiceAccount + opLog.Info(fmt.Sprintf("Checking `lagoon-deployer` ServiceAccount exists: %s", lagoonBuild.ObjectMeta.Name)) + serviceAccount := &corev1.ServiceAccount{} + err = r.getOrCreateServiceAccount(ctx, serviceAccount, namespace.ObjectMeta.Name) if err != nil { - if err := r.Create(ctx, saRoleBinding); err != nil { - return err - } - } - return nil -} - -// getOrCreateNamespace will create the namespace if it doesn't exist. -func (r *LagoonBuildReconciler) getOrCreateNamespace(ctx context.Context, namespace *corev1.Namespace, spec lagoonv1alpha1.LagoonBuildSpec) error { - // parse the project/env through the project pattern, or use the default - var err error - nsPattern := spec.Project.NamespacePattern - if spec.Project.NamespacePattern == "" { - nsPattern = DefaultNamespacePattern - } - // lowercase and dnsify the namespace against the namespace pattern - ns := makeSafe( - strings.Replace( - strings.Replace( - nsPattern, - "${environment}", - spec.Project.Environment, - -1, - ), - "${project}", - spec.Project.Name, - -1, - ), - ) - // If there is a namespaceprefix defined, and random prefix is disabled - // then add the prefix to the namespace - if r.NamespacePrefix != "" && r.RandomNamespacePrefix == false { - ns = fmt.Sprintf("%s-%s", r.NamespacePrefix, ns) - } - // If the randomprefix is enabled, then add a prefix based on the hash of the controller namespace - if r.RandomNamespacePrefix { - ns = fmt.Sprintf("%s-%s", hashString(r.ControllerNamespace)[0:8], ns) - } - // Once the namespace is fully calculated, then truncate the generated namespace - // to 63 characters to not exceed the kubernetes namespace limit - if len(ns) > 63 { - ns = fmt.Sprintf("%s-%s", ns[0:58], hashString(ns)[0:4]) - } - nsLabels := map[string]string{ - "lagoon.sh/project": spec.Project.Name, - "lagoon.sh/environment": spec.Project.Environment, - "lagoon.sh/environmentType": spec.Project.EnvironmentType, - } - if spec.Project.ID != nil { - nsLabels["lagoon.sh/projectId"] = fmt.Sprintf("%d", *spec.Project.ID) + return ctrl.Result{}, err } - if spec.Project.EnvironmentID != nil { - nsLabels["lagoon.sh/environmentId"] = fmt.Sprintf("%d", *spec.Project.EnvironmentID) - } - // if it isn't an openshift build, then just create a normal namespace - // add the required lagoon labels to the namespace when creating - namespace.ObjectMeta = metav1.ObjectMeta{ - Name: ns, - Labels: nsLabels, + // ServiceAccount RoleBinding creation + opLog.Info(fmt.Sprintf("Checking `lagoon-deployer-admin` RoleBinding exists: %s", lagoonBuild.ObjectMeta.Name)) + saRoleBinding := &rbacv1.RoleBinding{} + err = r.getOrCreateSARoleBinding(ctx, saRoleBinding, namespace.ObjectMeta.Name) + if err != nil { + return ctrl.Result{}, err } - // this is an openshift build, then we need to create a projectrequest - // we use projectrequest so that we ensure any openshift specific things can happen. - if r.IsOpenshift { - projectRequest := &projectv1.ProjectRequest{} - projectRequest.ObjectMeta.Name = ns - projectRequest.DisplayName = fmt.Sprintf(`[%s] %s`, spec.Project.Name, spec.Project.Environment) - if err := r.Get(ctx, types.NamespacedName{Name: ns}, namespace); err != nil { - if err := r.Create(ctx, projectRequest); err != nil { - return err - } - } - // once the projectrequest is created, we should wait for the namespace to get created - // this should happen pretty quickly, but if it hasn't happened in a minute it probably failed - // this namespace check will also run to patch existing namespaces with labels when they are re-deployed - err = try.Do(func(attempt int) (bool, error) { - var err error - if err := r.Get(ctx, types.NamespacedName{Name: ns}, namespace); err != nil { - time.Sleep(10 * time.Second) // wait 10 seconds - } - return attempt < 6, err - }) + // create the service account role binding for openshift to allow promotions in the openshift 3.11 clusters + if r.IsOpenshift && lagoonBuild.Spec.Build.Type == "promote" { + err := r.getOrCreatePromoteSARoleBinding(ctx, lagoonBuild.Spec.Promote.SourceProject, namespace.ObjectMeta.Name) if err != nil { - return err - } - } else { - // if kubernetes, just create it if it doesn't exist - if err := r.Get(ctx, types.NamespacedName{Name: ns}, namespace); err != nil { - if err := r.Create(ctx, namespace); err != nil { - return err - } + return ctrl.Result{}, err } } - // once the namespace exists, then we can patch it with our labels - // this means the labels will always get added or updated if we need to change them or add new labels - // after the namespace has been created - mergePatch, _ := json.Marshal(map[string]interface{}{ - "metadata": map[string]interface{}{ - "labels": nsLabels, - }, - }) - if err := r.Patch(ctx, namespace, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { - return err - } - if err := r.Get(ctx, types.NamespacedName{Name: ns}, namespace); err != nil { - return err - } - // if local/regional harbor is enabled, and this is not an openshift 3 cluster - if r.LFFHarborEnabled && !r.IsOpenshift { - // create the harbor client - lagoonHarbor, err := NewHarbor(r.Harbor) - if err != nil { - return err - } - // create the project in harbor - hProject, err := lagoonHarbor.CreateProject(ctx, spec.Project.Name) - if err != nil { - return err - } - // create or refresh the robot credentials - robotCreds, err := lagoonHarbor.CreateOrRefreshRobot(ctx, - hProject, - spec.Project.Environment, - ns, - "lagoon-internal-registry-secret", - time.Now().Add(lagoonHarbor.RobotAccountExpiry).Unix()) - if err != nil { - return err - } - if robotCreds != nil { - // if we have robotcredentials to create, do that here - if err := upsertHarborSecret(ctx, r.Client, robotCreds); err != nil { - return err - } - } - } - return nil -} - -// getCreateOrUpdateSSHKeySecret will create or update the ssh key. -func (r *LagoonBuildReconciler) getCreateOrUpdateSSHKeySecret(ctx context.Context, - sshKey *corev1.Secret, - spec lagoonv1alpha1.LagoonBuildSpec, - ns string) error { - sshKey.ObjectMeta = metav1.ObjectMeta{ - Name: "lagoon-sshkey", - Namespace: ns, - } - sshKey.Type = "kubernetes.io/ssh-auth" - sshKey.Data = map[string][]byte{ - "ssh-privatekey": spec.Project.Key, - } - err := r.Get(ctx, types.NamespacedName{ - Namespace: ns, - Name: "lagoon-sshkey", - }, sshKey) + // copy the build resource into a new resource and set the status to pending + // create the new resource and the controller will handle it via queue + opLog.Info(fmt.Sprintf("Creating LagoonBuild in Pending status: %s", lagoonBuild.ObjectMeta.Name)) + err = r.getOrCreateBuildResource(ctx, &lagoonBuild, namespace.ObjectMeta.Name) if err != nil { - if err := r.Create(ctx, sshKey); err != nil { - return err - } - } - // if the keys are different, then load in the new key from the spec - if bytes.Compare(sshKey.Data["ssh-privatekey"], spec.Project.Key) != 0 { - sshKey.Data = map[string][]byte{ - "ssh-privatekey": spec.Project.Key, - } - if err := r.Update(ctx, sshKey); err != nil { - return err - } + return ctrl.Result{}, err } - return nil + + // if everything is all good controller will handle the new build resource that gets created as it will have + // the `lagoon.sh/buildStatus = Pending` now + // so end this reconcile process + pendingBuilds := &lagoonv1alpha1.LagoonBuildList{} + return ctrl.Result{}, cancelExtraBuilds(ctx, r, opLog, pendingBuilds, namespace.ObjectMeta.Name, "Pending") + // return ctrl.Result{}, nil } // getOrCreateBuildResource will deepcopy the lagoon build into a new resource and push it to the new namespace @@ -1021,86 +215,3 @@ func (r *LagoonBuildReconciler) getOrCreateBuildResource(ctx context.Context, bu } return nil } - -// getOrCreatePromoteSARoleBinding will create the rolebinding for openshift promotions to be used by the lagoon-deployer service account. -func (r *LagoonBuildReconciler) getOrCreatePromoteSARoleBinding(ctx context.Context, sourcens string, ns string) error { - viewRoleBinding := &rbacv1.RoleBinding{} - viewRoleBinding.ObjectMeta = metav1.ObjectMeta{ - Name: fmt.Sprintf("%s-lagoon-deployer-view", ns), - Namespace: sourcens, - } - viewRoleBinding.RoleRef = rbacv1.RoleRef{ - Name: "view", - Kind: "ClusterRole", - APIGroup: "rbac.authorization.k8s.io", - } - viewRoleBinding.Subjects = []rbacv1.Subject{ - { - Name: "lagoon-deployer", - Kind: "ServiceAccount", - Namespace: ns, - }, - } - err := r.Get(ctx, types.NamespacedName{ - Namespace: sourcens, - Name: fmt.Sprintf("%s-lagoon-deployer-view", ns), - }, viewRoleBinding) - if err != nil { - if err := r.Create(ctx, viewRoleBinding); err != nil { - return err - } - } - imagePullRoleBinding := &rbacv1.RoleBinding{} - imagePullRoleBinding.ObjectMeta = metav1.ObjectMeta{ - Name: fmt.Sprintf("%s-lagoon-deployer-image-puller", ns), - Namespace: sourcens, - } - imagePullRoleBinding.RoleRef = rbacv1.RoleRef{ - Name: "system:image-puller", - Kind: "ClusterRole", - APIGroup: "rbac.authorization.k8s.io", - } - imagePullRoleBinding.Subjects = []rbacv1.Subject{ - { - Name: "lagoon-deployer", - Kind: "ServiceAccount", - Namespace: ns, - }, - } - err = r.Get(ctx, types.NamespacedName{ - Namespace: sourcens, - Name: fmt.Sprintf("%s-lagoon-deployer-image-puller", ns), - }, imagePullRoleBinding) - if err != nil { - if err := r.Create(ctx, imagePullRoleBinding); err != nil { - return err - } - } - defaultImagePullRoleBinding := &rbacv1.RoleBinding{} - defaultImagePullRoleBinding.ObjectMeta = metav1.ObjectMeta{ - Name: fmt.Sprintf("%s-lagoon-deployer-default-image-puller", ns), - Namespace: sourcens, - } - defaultImagePullRoleBinding.RoleRef = rbacv1.RoleRef{ - Name: "system:image-puller", - Kind: "ClusterRole", - APIGroup: "rbac.authorization.k8s.io", - } - defaultImagePullRoleBinding.Subjects = []rbacv1.Subject{ - { - Name: "lagoon-deployer", - Kind: "ServiceAccount", - Namespace: ns, - }, - } - err = r.Get(ctx, types.NamespacedName{ - Namespace: sourcens, - Name: fmt.Sprintf("%s-lagoon-deployer-default-image-puller", ns), - }, defaultImagePullRoleBinding) - if err != nil { - if err := r.Create(ctx, defaultImagePullRoleBinding); err != nil { - return err - } - } - return nil -} diff --git a/controllers/lagoonbuild_helpers.go b/controllers/lagoonbuild_helpers.go new file mode 100644 index 00000000..9500caff --- /dev/null +++ b/controllers/lagoonbuild_helpers.go @@ -0,0 +1,855 @@ +package controllers + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "regexp" + "strconv" + "strings" + "time" + + "gopkg.in/matryer/try.v1" + corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" + "github.com/go-logr/logr" + + // Openshift + projectv1 "github.com/openshift/api/project/v1" +) + +// updateBuildStatusCondition is used to patch the lagoon build with the status conditions for the build, plus any logs +func (r *LagoonBuildReconciler) updateBuildStatusCondition(ctx context.Context, + lagoonBuild *lagoonv1alpha1.LagoonBuild, + condition lagoonv1alpha1.LagoonConditions, + log []byte, +) error { + // set the transition time + condition.LastTransitionTime = time.Now().UTC().Format(time.RFC3339) + if !jobContainsStatus(lagoonBuild.Status.Conditions, condition) { + lagoonBuild.Status.Conditions = append(lagoonBuild.Status.Conditions, condition) + mergePatch, _ := json.Marshal(map[string]interface{}{ + "status": map[string]interface{}{ + "conditions": lagoonBuild.Status.Conditions, + "log": log, + }, + }) + if err := r.Patch(ctx, lagoonBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + return fmt.Errorf("Unable to update status condition: %v", err) + } + } + return nil +} + +// getOrCreateServiceAccount will create the lagoon-deployer service account if it doesn't exist. +func (r *LagoonBuildReconciler) getOrCreateServiceAccount(ctx context.Context, serviceAccount *corev1.ServiceAccount, ns string) error { + serviceAccount.ObjectMeta = metav1.ObjectMeta{ + Name: "lagoon-deployer", + Namespace: ns, + } + err := r.Get(ctx, types.NamespacedName{ + Namespace: ns, + Name: "lagoon-deployer", + }, serviceAccount) + if err != nil { + if err := r.Create(ctx, serviceAccount); err != nil { + return err + } + } + return nil +} + +// getOrCreateSARoleBinding will create the rolebinding for the lagoon-deployer if it doesn't exist. +func (r *LagoonBuildReconciler) getOrCreateSARoleBinding(ctx context.Context, saRoleBinding *rbacv1.RoleBinding, ns string) error { + saRoleBinding.ObjectMeta = metav1.ObjectMeta{ + Name: "lagoon-deployer-admin", + Namespace: ns, + } + saRoleBinding.RoleRef = rbacv1.RoleRef{ + Name: "admin", + Kind: "ClusterRole", + APIGroup: "rbac.authorization.k8s.io", + } + saRoleBinding.Subjects = []rbacv1.Subject{ + { + Name: "lagoon-deployer", + Kind: "ServiceAccount", + Namespace: ns, + }, + } + err := r.Get(ctx, types.NamespacedName{ + Namespace: ns, + Name: "lagoon-deployer-admin", + }, saRoleBinding) + if err != nil { + if err := r.Create(ctx, saRoleBinding); err != nil { + return err + } + } + return nil +} + +// getOrCreateNamespace will create the namespace if it doesn't exist. +func (r *LagoonBuildReconciler) getOrCreateNamespace(ctx context.Context, namespace *corev1.Namespace, spec lagoonv1alpha1.LagoonBuildSpec) error { + // parse the project/env through the project pattern, or use the default + var err error + nsPattern := spec.Project.NamespacePattern + if spec.Project.NamespacePattern == "" { + nsPattern = DefaultNamespacePattern + } + // lowercase and dnsify the namespace against the namespace pattern + ns := makeSafe( + strings.Replace( + strings.Replace( + nsPattern, + "${environment}", + spec.Project.Environment, + -1, + ), + "${project}", + spec.Project.Name, + -1, + ), + ) + // If there is a namespaceprefix defined, and random prefix is disabled + // then add the prefix to the namespace + if r.NamespacePrefix != "" && r.RandomNamespacePrefix == false { + ns = fmt.Sprintf("%s-%s", r.NamespacePrefix, ns) + } + // If the randomprefix is enabled, then add a prefix based on the hash of the controller namespace + if r.RandomNamespacePrefix { + ns = fmt.Sprintf("%s-%s", hashString(r.ControllerNamespace)[0:8], ns) + } + // Once the namespace is fully calculated, then truncate the generated namespace + // to 63 characters to not exceed the kubernetes namespace limit + if len(ns) > 63 { + ns = fmt.Sprintf("%s-%s", ns[0:58], hashString(ns)[0:4]) + } + nsLabels := map[string]string{ + "lagoon.sh/project": spec.Project.Name, + "lagoon.sh/environment": spec.Project.Environment, + "lagoon.sh/environmentType": spec.Project.EnvironmentType, + } + if spec.Project.ID != nil { + nsLabels["lagoon.sh/projectId"] = fmt.Sprintf("%d", *spec.Project.ID) + } + if spec.Project.EnvironmentID != nil { + nsLabels["lagoon.sh/environmentId"] = fmt.Sprintf("%d", *spec.Project.EnvironmentID) + } + // if it isn't an openshift build, then just create a normal namespace + // add the required lagoon labels to the namespace when creating + namespace.ObjectMeta = metav1.ObjectMeta{ + Name: ns, + Labels: nsLabels, + } + // this is an openshift build, then we need to create a projectrequest + // we use projectrequest so that we ensure any openshift specific things can happen. + if r.IsOpenshift { + projectRequest := &projectv1.ProjectRequest{} + projectRequest.ObjectMeta.Name = ns + projectRequest.DisplayName = fmt.Sprintf(`[%s] %s`, spec.Project.Name, spec.Project.Environment) + if err := r.Get(ctx, types.NamespacedName{Name: ns}, namespace); err != nil { + if err := r.Create(ctx, projectRequest); err != nil { + return err + } + } + // once the projectrequest is created, we should wait for the namespace to get created + // this should happen pretty quickly, but if it hasn't happened in a minute it probably failed + // this namespace check will also run to patch existing namespaces with labels when they are re-deployed + err = try.Do(func(attempt int) (bool, error) { + var err error + if err := r.Get(ctx, types.NamespacedName{Name: ns}, namespace); err != nil { + time.Sleep(10 * time.Second) // wait 10 seconds + } + return attempt < 6, err + }) + if err != nil { + return err + } + } else { + // if kubernetes, just create it if it doesn't exist + if err := r.Get(ctx, types.NamespacedName{Name: ns}, namespace); err != nil { + if err := r.Create(ctx, namespace); err != nil { + return err + } + } + } + // once the namespace exists, then we can patch it with our labels + // this means the labels will always get added or updated if we need to change them or add new labels + // after the namespace has been created + mergePatch, _ := json.Marshal(map[string]interface{}{ + "metadata": map[string]interface{}{ + "labels": nsLabels, + }, + }) + if err := r.Patch(ctx, namespace, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + return err + } + if err := r.Get(ctx, types.NamespacedName{Name: ns}, namespace); err != nil { + return err + } + + // if local/regional harbor is enabled, and this is not an openshift 3 cluster + if r.LFFHarborEnabled && !r.IsOpenshift { + // create the harbor client + lagoonHarbor, err := NewHarbor(r.Harbor) + if err != nil { + return err + } + // create the project in harbor + hProject, err := lagoonHarbor.CreateProject(ctx, spec.Project.Name) + if err != nil { + return err + } + // create or refresh the robot credentials + robotCreds, err := lagoonHarbor.CreateOrRefreshRobot(ctx, + hProject, + spec.Project.Environment, + ns, + "lagoon-internal-registry-secret", + time.Now().Add(lagoonHarbor.RobotAccountExpiry).Unix()) + if err != nil { + return err + } + if robotCreds != nil { + // if we have robotcredentials to create, do that here + if err := upsertHarborSecret(ctx, r.Client, robotCreds); err != nil { + return err + } + } + } + return nil +} + +// getCreateOrUpdateSSHKeySecret will create or update the ssh key. +func (r *LagoonBuildReconciler) getCreateOrUpdateSSHKeySecret(ctx context.Context, + sshKey *corev1.Secret, + spec lagoonv1alpha1.LagoonBuildSpec, + ns string) error { + sshKey.ObjectMeta = metav1.ObjectMeta{ + Name: "lagoon-sshkey", + Namespace: ns, + } + sshKey.Type = "kubernetes.io/ssh-auth" + sshKey.Data = map[string][]byte{ + "ssh-privatekey": spec.Project.Key, + } + err := r.Get(ctx, types.NamespacedName{ + Namespace: ns, + Name: "lagoon-sshkey", + }, sshKey) + if err != nil { + if err := r.Create(ctx, sshKey); err != nil { + return err + } + } + // if the keys are different, then load in the new key from the spec + if bytes.Compare(sshKey.Data["ssh-privatekey"], spec.Project.Key) != 0 { + sshKey.Data = map[string][]byte{ + "ssh-privatekey": spec.Project.Key, + } + if err := r.Update(ctx, sshKey); err != nil { + return err + } + } + return nil +} + +// getOrCreatePromoteSARoleBinding will create the rolebinding for openshift promotions to be used by the lagoon-deployer service account. +func (r *LagoonBuildReconciler) getOrCreatePromoteSARoleBinding(ctx context.Context, sourcens string, ns string) error { + viewRoleBinding := &rbacv1.RoleBinding{} + viewRoleBinding.ObjectMeta = metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-lagoon-deployer-view", ns), + Namespace: sourcens, + } + viewRoleBinding.RoleRef = rbacv1.RoleRef{ + Name: "view", + Kind: "ClusterRole", + APIGroup: "rbac.authorization.k8s.io", + } + viewRoleBinding.Subjects = []rbacv1.Subject{ + { + Name: "lagoon-deployer", + Kind: "ServiceAccount", + Namespace: ns, + }, + } + err := r.Get(ctx, types.NamespacedName{ + Namespace: sourcens, + Name: fmt.Sprintf("%s-lagoon-deployer-view", ns), + }, viewRoleBinding) + if err != nil { + if err := r.Create(ctx, viewRoleBinding); err != nil { + return err + } + } + imagePullRoleBinding := &rbacv1.RoleBinding{} + imagePullRoleBinding.ObjectMeta = metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-lagoon-deployer-image-puller", ns), + Namespace: sourcens, + } + imagePullRoleBinding.RoleRef = rbacv1.RoleRef{ + Name: "system:image-puller", + Kind: "ClusterRole", + APIGroup: "rbac.authorization.k8s.io", + } + imagePullRoleBinding.Subjects = []rbacv1.Subject{ + { + Name: "lagoon-deployer", + Kind: "ServiceAccount", + Namespace: ns, + }, + } + err = r.Get(ctx, types.NamespacedName{ + Namespace: sourcens, + Name: fmt.Sprintf("%s-lagoon-deployer-image-puller", ns), + }, imagePullRoleBinding) + if err != nil { + if err := r.Create(ctx, imagePullRoleBinding); err != nil { + return err + } + } + defaultImagePullRoleBinding := &rbacv1.RoleBinding{} + defaultImagePullRoleBinding.ObjectMeta = metav1.ObjectMeta{ + Name: fmt.Sprintf("%s-lagoon-deployer-default-image-puller", ns), + Namespace: sourcens, + } + defaultImagePullRoleBinding.RoleRef = rbacv1.RoleRef{ + Name: "system:image-puller", + Kind: "ClusterRole", + APIGroup: "rbac.authorization.k8s.io", + } + defaultImagePullRoleBinding.Subjects = []rbacv1.Subject{ + { + Name: "lagoon-deployer", + Kind: "ServiceAccount", + Namespace: ns, + }, + } + err = r.Get(ctx, types.NamespacedName{ + Namespace: sourcens, + Name: fmt.Sprintf("%s-lagoon-deployer-default-image-puller", ns), + }, defaultImagePullRoleBinding) + if err != nil { + if err := r.Create(ctx, defaultImagePullRoleBinding); err != nil { + return err + } + } + return nil +} + +// processBuild will actually process the build. +func (r *LagoonBuildReconciler) processBuild(ctx context.Context, opLog logr.Logger, lagoonBuild lagoonv1alpha1.LagoonBuild) error { + // we run these steps again just to be sure that it gets updated/created if it hasn't already + opLog.Info(fmt.Sprintf("Starting work on build: %s", lagoonBuild.ObjectMeta.Name)) + // create the lagoon-sshkey secret + sshKey := &corev1.Secret{} + opLog.Info(fmt.Sprintf("Checking `lagoon-sshkey` Secret exists: %s", lagoonBuild.ObjectMeta.Name)) + err := r.getCreateOrUpdateSSHKeySecret(ctx, sshKey, lagoonBuild.Spec, lagoonBuild.ObjectMeta.Namespace) + if err != nil { + return err + } + + // create the `lagoon-deployer` ServiceAccount + opLog.Info(fmt.Sprintf("Checking `lagoon-deployer` ServiceAccount exists: %s", lagoonBuild.ObjectMeta.Name)) + serviceAccount := &corev1.ServiceAccount{} + err = r.getOrCreateServiceAccount(ctx, serviceAccount, lagoonBuild.ObjectMeta.Namespace) + if err != nil { + return err + } + + // ServiceAccount RoleBinding creation + opLog.Info(fmt.Sprintf("Checking `lagoon-deployer-admin` RoleBinding exists: %s", lagoonBuild.ObjectMeta.Name)) + saRoleBinding := &rbacv1.RoleBinding{} + err = r.getOrCreateSARoleBinding(ctx, saRoleBinding, lagoonBuild.ObjectMeta.Namespace) + if err != nil { + return err + } + + if r.IsOpenshift && lagoonBuild.Spec.Build.Type == "promote" { + err := r.getOrCreatePromoteSARoleBinding(ctx, lagoonBuild.Spec.Promote.SourceProject, lagoonBuild.ObjectMeta.Namespace) + if err != nil { + return err + } + } + + opLog.Info(fmt.Sprintf("Checking `lagoon-deployer` Token exists: %s", lagoonBuild.ObjectMeta.Name)) + var serviceaccountTokenSecret string + for _, secret := range serviceAccount.Secrets { + match, _ := regexp.MatchString("^lagoon-deployer-token", secret.Name) + if match { + serviceaccountTokenSecret = secret.Name + break + } + } + if serviceaccountTokenSecret == "" { + return fmt.Errorf("Could not find token secret for ServiceAccount lagoon-deployer") + } + + // openshift uses a builder service account to be able to push images to the openshift registry + // lets load this in exactly the same way an openshift build would + var builderServiceaccountTokenSecret string + if r.IsOpenshift { + builderAccount := &corev1.ServiceAccount{} + err := r.Get(ctx, types.NamespacedName{ + Namespace: lagoonBuild.ObjectMeta.Namespace, + Name: "builder", + }, builderAccount) + if err != nil { + return fmt.Errorf("Could not find ServiceAccount builder") + } + opLog.Info(fmt.Sprintf("Checking `builder` Token exists: %s", lagoonBuild.ObjectMeta.Name)) + for _, secret := range builderAccount.Secrets { + match, _ := regexp.MatchString("^builder-token", secret.Name) + if match { + builderServiceaccountTokenSecret = secret.Name + break + } + } + if builderServiceaccountTokenSecret == "" { + return fmt.Errorf("Could not find token secret for ServiceAccount builder") + } + } + + // create the Pod that will do the work + podEnvs := []corev1.EnvVar{ + { + Name: "SOURCE_REPOSITORY", + Value: lagoonBuild.Spec.Project.GitURL, + }, + { + Name: "GIT_REF", + Value: lagoonBuild.Spec.GitReference, + }, + { + Name: "SUBFOLDER", + Value: lagoonBuild.Spec.Project.SubFolder, + }, + { + Name: "BRANCH", + Value: lagoonBuild.Spec.Branch.Name, + }, + { + Name: "PROJECT", + Value: lagoonBuild.Spec.Project.Name, + }, + { + Name: "ENVIRONMENT_TYPE", + Value: lagoonBuild.Spec.Project.EnvironmentType, + }, + { + Name: "ACTIVE_ENVIRONMENT", + Value: lagoonBuild.Spec.Project.ProductionEnvironment, + }, + { + Name: "STANDBY_ENVIRONMENT", + Value: lagoonBuild.Spec.Project.StandbyEnvironment, + }, + { + Name: "PROJECT_SECRET", + Value: lagoonBuild.Spec.Project.ProjectSecret, + }, + { + Name: "MONITORING_ALERTCONTACT", + Value: lagoonBuild.Spec.Project.Monitoring.Contact, + }, + { + Name: "MONTHLY_BACKUP_DEFAULT_RETENTION", + Value: strconv.Itoa(r.BackupDefaultMonthlyRetention), + }, + { + Name: "WEEKLY_BACKUP_DEFAULT_RETENTION", + Value: strconv.Itoa(r.BackupDefaultWeeklyRetention), + }, + { + Name: "DAILY_BACKUP_DEFAULT_RETENTION", + Value: strconv.Itoa(r.BackupDefaultDailyRetention), + }, + { + Name: "K8UP_WEEKLY_RANDOM_FEATURE_FLAG", + Value: strconv.FormatBool(r.LFFBackupWeeklyRandom), + }, + } + if r.IsOpenshift { + // openshift builds have different names for some things, and also additional values to add + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "TYPE", + Value: lagoonBuild.Spec.Build.Type, + }) + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "SAFE_BRANCH", + Value: lagoonBuild.Spec.Project.Environment, + }) + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "SAFE_PROJECT", + Value: makeSafe(lagoonBuild.Spec.Project.Name), + }) + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "OPENSHIFT_NAME", + Value: lagoonBuild.Spec.Project.DeployTarget, + }) + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "ROUTER_URL", + Value: strings.ToLower( + strings.Replace( + strings.Replace( + lagoonBuild.Spec.Project.RouterPattern, + "${branch}", + lagoonBuild.Spec.Project.Environment, + -1, + ), + "${project}", + lagoonBuild.Spec.Project.Name, + -1, + ), + ), + }) + } else { + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "BUILD_TYPE", + Value: lagoonBuild.Spec.Build.Type, + }) + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "ENVIRONMENT", + Value: lagoonBuild.Spec.Project.Environment, + }) + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "KUBERNETES", + Value: lagoonBuild.Spec.Project.DeployTarget, + }) + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "REGISTRY", + Value: lagoonBuild.Spec.Project.Registry, + }) + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "ROUTER_URL", + Value: strings.ToLower( + strings.Replace( + strings.Replace( + lagoonBuild.Spec.Project.RouterPattern, + "${environment}", + lagoonBuild.Spec.Project.Environment, + -1, + ), + "${project}", + lagoonBuild.Spec.Project.Name, + -1, + ), + ), + }) + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "SHORT_ROUTER_URL", + Value: strings.ToLower( + strings.Replace( + strings.Replace( + lagoonBuild.Spec.Project.RouterPattern, + "${environment}", + shortName(lagoonBuild.Spec.Project.Environment), + -1, + ), + "${project}", + shortName(lagoonBuild.Spec.Project.Name), + -1, + ), + ), + }) + } + if lagoonBuild.Spec.Build.CI != "" { + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "CI", + Value: lagoonBuild.Spec.Build.CI, + }) + } + if lagoonBuild.Spec.Build.Type == "pullrequest" { + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "PR_HEAD_BRANCH", + Value: lagoonBuild.Spec.Pullrequest.HeadBranch, + }) + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "PR_HEAD_SHA", + Value: lagoonBuild.Spec.Pullrequest.HeadSha, + }) + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "PR_BASE_BRANCH", + Value: lagoonBuild.Spec.Pullrequest.BaseBranch, + }) + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "PR_BASE_SHA", + Value: lagoonBuild.Spec.Pullrequest.BaseSha, + }) + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "PR_TITLE", + Value: lagoonBuild.Spec.Pullrequest.Title, + }) + if !r.IsOpenshift { + // we don't use PR_NUMBER in openshift builds + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "PR_NUMBER", + Value: string(lagoonBuild.Spec.Pullrequest.Number), + }) + } + } + if lagoonBuild.Spec.Build.Type == "promote" { + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "PROMOTION_SOURCE_ENVIRONMENT", + Value: lagoonBuild.Spec.Promote.SourceEnvironment, + }) + if r.IsOpenshift { + // openshift does promotions differently + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "PROMOTION_SOURCE_OPENSHIFT_PROJECT", + Value: lagoonBuild.Spec.Promote.SourceProject, + }) + } + } + // if local/regional harbor is enabled, and this is not an openshift 3 cluster + if r.LFFHarborEnabled && !r.IsOpenshift { + // unmarshal the project variables + lagoonProjectVariables := &[]LagoonEnvironmentVariable{} + lagoonEnvironmentVariables := &[]LagoonEnvironmentVariable{} + json.Unmarshal(lagoonBuild.Spec.Project.Variables.Project, lagoonProjectVariables) + json.Unmarshal(lagoonBuild.Spec.Project.Variables.Environment, lagoonEnvironmentVariables) + // check if INTERNAL_REGISTRY_SOURCE_LAGOON is defined, and if it isn't true + // if this value is true, then we want to use what is provided by Lagoon + // if it is false, or not set, then we use what is provided by this controller + // this allows us to make it so a specific environment or the project entirely + // can still use whats provided by lagoon + if !variableExists(lagoonProjectVariables, "INTERNAL_REGISTRY_SOURCE_LAGOON", "true") || + !variableExists(lagoonEnvironmentVariables, "INTERNAL_REGISTRY_SOURCE_LAGOON", "true") { + // source the robot credential, and inject it into the lagoon project variables + // this will overwrite what is provided by lagoon (if lagoon has provided them) + // or it will add them. + robotCredential := &corev1.Secret{} + if err = r.Get(ctx, types.NamespacedName{ + Namespace: lagoonBuild.ObjectMeta.Namespace, + Name: "lagoon-internal-registry-secret", + }, robotCredential); err != nil { + return fmt.Errorf("Could not find Harbor RobotAccount credential") + } + auths := Auths{} + if secretData, ok := robotCredential.Data[".dockerconfigjson"]; ok { + if err := json.Unmarshal(secretData, &auths); err != nil { + return fmt.Errorf("Could not unmarshal Harbor RobotAccount credential") + } + if len(auths.Registries) == 1 { + for registry, creds := range auths.Registries { + replaceOrAddVariable(lagoonProjectVariables, "INTERNAL_REGISTRY_URL", registry, "internal_container_registry") + replaceOrAddVariable(lagoonProjectVariables, "INTERNAL_REGISTRY_USERNAME", creds.Username, "internal_container_registry") + replaceOrAddVariable(lagoonProjectVariables, "INTERNAL_REGISTRY_PASSWORD", creds.Password, "internal_container_registry") + } + } + } + // marshal any changes into the project spec on the fly, don't save the spec though + // these values are being overwritten and injected directly into the build pod to be consumed + // by the build pod image + lagoonBuild.Spec.Project.Variables.Project, _ = json.Marshal(lagoonProjectVariables) + } + } + if lagoonBuild.Spec.Project.Variables.Project != nil { + // if this is 2 bytes long, then it means its just an empty json array + // we only want to add it if it is more than 2 bytes + if len(lagoonBuild.Spec.Project.Variables.Project) > 2 { + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "LAGOON_PROJECT_VARIABLES", + Value: string(lagoonBuild.Spec.Project.Variables.Project), + }) + } + } + if lagoonBuild.Spec.Project.Variables.Environment != nil { + // if this is 2 bytes long, then it means its just an empty json array + // we only want to add it if it is more than 2 bytes + if len(lagoonBuild.Spec.Project.Variables.Environment) > 2 { + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "LAGOON_ENVIRONMENT_VARIABLES", + Value: string(lagoonBuild.Spec.Project.Variables.Environment), + }) + } + } + if lagoonBuild.Spec.Project.Monitoring.StatuspageID != "" { + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "MONITORING_STATUSPAGEID", + Value: lagoonBuild.Spec.Project.Monitoring.StatuspageID, + }) + } + // if the fastly watch status is set on the controller, inject the fastly service ID into the build pod to be consumed + // by the build-depoy-dind image + if r.FastlyWatchStatus { + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "LAGOON_FASTLY_NOCACHE_SERVICE_ID", + Value: r.FastlyServiceID, + }) + } + // Set any defined Lagoon feature flags in the build environment. + if r.LFFForceRootlessWorkload != "" { + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "LAGOON_FEATURE_FLAG_FORCE_ROOTLESS_WORKLOAD", + Value: r.LFFForceRootlessWorkload, + }) + } + if r.LFFDefaultRootlessWorkload != "" { + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "LAGOON_FEATURE_FLAG_DEFAULT_ROOTLESS_WORKLOAD", + Value: r.LFFDefaultRootlessWorkload, + }) + } + if r.LFFForceIsolationNetworkPolicy != "" { + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "LAGOON_FEATURE_FLAG_FORCE_ISOLATION_NETWORK_POLICY", + Value: r.LFFForceIsolationNetworkPolicy, + }) + } + if r.LFFDefaultIsolationNetworkPolicy != "" { + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "LAGOON_FEATURE_FLAG_DEFAULT_ISOLATION_NETWORK_POLICY", + Value: r.LFFDefaultIsolationNetworkPolicy, + }) + } + // Use the build image in the controller definition + buildImage := r.BuildImage + if lagoonBuild.Spec.Build.Image != "" { + // otherwise if the build spec contains an image definition, use it instead. + buildImage = lagoonBuild.Spec.Build.Image + } + newPod := &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: lagoonBuild.ObjectMeta.Name, + Namespace: lagoonBuild.ObjectMeta.Namespace, + Labels: map[string]string{ + "lagoon.sh/jobType": "build", + "lagoon.sh/buildName": lagoonBuild.ObjectMeta.Name, + "lagoon.sh/controller": r.ControllerNamespace, + "lagoon.sh/buildRemoteID": string(lagoonBuild.ObjectMeta.UID), + }, + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: fmt.Sprintf("%v", lagoonv1alpha1.GroupVersion), + Kind: "LagoonBuild", + Name: lagoonBuild.ObjectMeta.Name, + UID: lagoonBuild.UID, + }, + }, + }, + Spec: corev1.PodSpec{ + RestartPolicy: "Never", + Volumes: []corev1.Volume{ + { + Name: serviceaccountTokenSecret, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: serviceaccountTokenSecret, + DefaultMode: intPtr(420), + }, + }, + }, + { + Name: "lagoon-sshkey", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: "lagoon-sshkey", + DefaultMode: intPtr(420), + }, + }, + }, + }, + Tolerations: []corev1.Toleration{ + { + Key: "lagoon/build", + Effect: "NoSchedule", + Operator: "Exists", + }, + { + Key: "lagoon/build", + Effect: "PreferNoSchedule", + Operator: "Exists", + }, + { + Key: "lagoon.sh/build", + Effect: "NoSchedule", + Operator: "Exists", + }, + { + Key: "lagoon.sh/build", + Effect: "PreferNoSchedule", + Operator: "Exists", + }, + }, + Containers: []corev1.Container{ + { + Name: "lagoon-build", + Image: buildImage, + ImagePullPolicy: "Always", + Env: podEnvs, + VolumeMounts: []corev1.VolumeMount{ + { + Name: serviceaccountTokenSecret, + ReadOnly: true, + MountPath: "/var/run/secrets/lagoon/deployer", + }, + { + Name: "lagoon-sshkey", + ReadOnly: true, + MountPath: "/var/run/secrets/lagoon/ssh", + }, + }, + }, + }, + }, + } + + // set the pod security context, if defined to a non-default value + if r.BuildPodRunAsUser != 0 || r.BuildPodRunAsGroup != 0 || + r.BuildPodFSGroup != 0 { + newPod.Spec.SecurityContext = &corev1.PodSecurityContext{ + RunAsUser: &r.BuildPodRunAsUser, + RunAsGroup: &r.BuildPodRunAsGroup, + FSGroup: &r.BuildPodFSGroup, + } + } + + // openshift uses a builder service account to be able to push images to the openshift registry + // load that into the podspec here + if r.IsOpenshift { + newPod.Spec.ServiceAccountName = "builder" + builderToken := corev1.VolumeMount{ + Name: builderServiceaccountTokenSecret, + ReadOnly: true, + MountPath: "/var/run/secrets/kubernetes.io/serviceaccount", + } + builderVolume := corev1.Volume{ + Name: builderServiceaccountTokenSecret, + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: builderServiceaccountTokenSecret, + DefaultMode: intPtr(420), + }, + }, + } + newPod.Spec.Volumes = append(newPod.Spec.Volumes, builderVolume) + newPod.Spec.Containers[0].VolumeMounts = append(newPod.Spec.Containers[0].VolumeMounts, builderToken) + } + opLog.Info(fmt.Sprintf("Checking build pod for: %s", lagoonBuild.ObjectMeta.Name)) + // once the pod spec has been defined, check if it isn't already created + err = r.Get(ctx, types.NamespacedName{ + Namespace: lagoonBuild.ObjectMeta.Namespace, + Name: newPod.ObjectMeta.Name, + }, newPod) + if err != nil { + // if it doesn't exist, then create the build pod + opLog.Info(fmt.Sprintf("Creating build pod for: %s", lagoonBuild.ObjectMeta.Name)) + if err := r.Create(ctx, newPod); err != nil { + opLog.Error(err, fmt.Sprintf("Unable to create build pod")) + // log the error and just exit, don't continue to try and do anything + // @TODO: should update the build to failed + return nil + } + // then break out of the build + } + opLog.Info(fmt.Sprintf("Build pod already running for: %s", lagoonBuild.ObjectMeta.Name)) + return nil +} diff --git a/controllers/lagoonbuild_qoshandler.go b/controllers/lagoonbuild_qoshandler.go new file mode 100644 index 00000000..d067b23f --- /dev/null +++ b/controllers/lagoonbuild_qoshandler.go @@ -0,0 +1,24 @@ +package controllers + +import ( + "context" + + lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" + "github.com/go-logr/logr" + ctrl "sigs.k8s.io/controller-runtime" +) + +// BuildQoS is use for the quality of service configuration for lagoon builds. +type BuildQoS struct { + MaxBuilds int + DefaultValue int +} + +func (r *LagoonBuildReconciler) qosBuildProcessor(ctx context.Context, + opLog logr.Logger, + lagoonBuild lagoonv1alpha1.LagoonBuild, + req ctrl.Request) (ctrl.Result, error) { + + // handle the QoS build process here + return ctrl.Result{}, nil +} diff --git a/controllers/lagoonbuild_standardhandler.go b/controllers/lagoonbuild_standardhandler.go new file mode 100644 index 00000000..06e850ff --- /dev/null +++ b/controllers/lagoonbuild_standardhandler.go @@ -0,0 +1,71 @@ +package controllers + +import ( + "context" + "encoding/json" + "fmt" + + lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" + "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/types" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func (r *LagoonBuildReconciler) standardBuildProcessor(ctx context.Context, + opLog logr.Logger, + lagoonBuild lagoonv1alpha1.LagoonBuild, + req ctrl.Request) (ctrl.Result, error) { + // check if we get a lagoonbuild that hasn't got any buildstatus + // this means it was created by the message queue handler + // so we should do the steps required for a lagoon build and then copy the build + // into the created namespace + if _, ok := lagoonBuild.ObjectMeta.Labels["lagoon.sh/buildStatus"]; !ok { + return r.createNamespaceBuild(ctx, opLog, lagoonBuild) + } + + // if we do have a `lagoon.sh/buildStatus` set, then process as normal + runningBuilds := &lagoonv1alpha1.LagoonBuildList{} + listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ + client.InNamespace(req.Namespace), + client.MatchingLabels(map[string]string{ + "lagoon.sh/buildStatus": "Running", + "lagoon.sh/controller": r.ControllerNamespace, + }), + }) + // list any builds that are running + if err := r.List(ctx, runningBuilds, listOption); err != nil { + return ctrl.Result{}, fmt.Errorf("Unable to list builds in the namespace, there may be none or something went wrong: %v", err) + } + for _, runningBuild := range runningBuilds.Items { + // if the running build is the one from this request then process it + if lagoonBuild.ObjectMeta.Name == runningBuild.ObjectMeta.Name { + // actually process the build here + if err := r.processBuild(ctx, opLog, lagoonBuild); err != nil { + return ctrl.Result{}, err + } + } // end check if running build is current LagoonBuild + } // end loop for running builds + + // if there are no running builds, check if there are any pending builds + if len(runningBuilds.Items) == 0 { + pendingBuilds := &lagoonv1alpha1.LagoonBuildList{} + return ctrl.Result{}, cancelExtraBuilds(ctx, r.Client, opLog, pendingBuilds, req.Namespace, "Running") + } + // The object is not being deleted, so if it does not have our finalizer, + // then lets add the finalizer and update the object. This is equivalent + // registering our finalizer. + if !containsString(lagoonBuild.ObjectMeta.Finalizers, finalizerName) { + lagoonBuild.ObjectMeta.Finalizers = append(lagoonBuild.ObjectMeta.Finalizers, finalizerName) + // use patches to avoid update errors + mergePatch, _ := json.Marshal(map[string]interface{}{ + "metadata": map[string]interface{}{ + "finalizers": lagoonBuild.ObjectMeta.Finalizers, + }, + }) + if err := r.Patch(ctx, &lagoonBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + return ctrl.Result{}, err + } + } + return ctrl.Result{}, nil +} diff --git a/controllers/lagoonmonitor_controller.go b/controllers/lagoonmonitor_controller.go index 24b583f0..7dafec30 100644 --- a/controllers/lagoonmonitor_controller.go +++ b/controllers/lagoonmonitor_controller.go @@ -20,7 +20,6 @@ import ( "context" "fmt" "io" - "sort" lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" "github.com/amazeeio/lagoon-kbd/handlers" @@ -126,27 +125,7 @@ func (r *LagoonMonitorReconciler) Reconcile(req ctrl.Request) (ctrl.Result, erro } // if we have no running builds, then check for any pending builds if len(runningBuilds.Items) == 0 { - listOption = (&client.ListOptions{}).ApplyOptions([]client.ListOption{ - client.InNamespace(req.Namespace), - client.MatchingLabels(map[string]string{"lagoon.sh/buildStatus": "Pending"}), - }) - if err := r.List(ctx, pendingBuilds, listOption); err != nil { - return ctrl.Result{}, fmt.Errorf("Unable to list builds in the namespace, there may be none or something went wrong: %v", err) - } - opLog.Info(fmt.Sprintf("There are %v Pending builds", len(pendingBuilds.Items))) - // if we have any pending builds, then grab the first one from the items as they are sorted by oldest pending first - if len(pendingBuilds.Items) > 0 { - // sort the pending builds by creation timestamp - sort.Slice(pendingBuilds.Items, func(i, j int) bool { - return pendingBuilds.Items[i].ObjectMeta.CreationTimestamp.Before(&pendingBuilds.Items[j].ObjectMeta.CreationTimestamp) - }) - opLog.Info(fmt.Sprintf("Next build is: %s", pendingBuilds.Items[0].ObjectMeta.Name)) - pendingBuild := pendingBuilds.Items[0].DeepCopy() - pendingBuild.Labels["lagoon.sh/buildStatus"] = "Running" - if err := r.Update(ctx, pendingBuild); err != nil { - return ctrl.Result{}, err - } - } + return ctrl.Result{}, cancelExtraBuilds(ctx, r, opLog, pendingBuilds, req.Namespace, "Running") } } return ctrl.Result{}, nil diff --git a/main.go b/main.go index 4dde9300..303b1b18 100644 --- a/main.go +++ b/main.go @@ -116,6 +116,10 @@ func main() { var harborLagoonWebhook string var harborWebhookEventTypes string + var lffQoSEnabled bool + var qosMaxBuilds int + var qosDefaultValue int + flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.") flag.StringVar(&lagoonTargetName, "lagoon-target-name", "ci-local-control-k8s", @@ -224,6 +228,12 @@ func main() { "The webhook URL to add for Lagoon, this is where events notifications will be posted.") flag.StringVar(&harborWebhookEventTypes, "harbor-webhook-eventtypes", "SCANNING_FAILED,SCANNING_COMPLETED", "The event types to use for the Lagoon webhook") + + // QoS configuration + flag.BoolVar(&lffQoSEnabled, "enable-qos", false, "Flag to enable this controller with QoS for builds.") + flag.IntVar(&qosMaxBuilds, "qos-max-builds", 20, "The number of builds that can run at any one time.") + flag.IntVar(&qosDefaultValue, "qos-default", 5, "The default qos value to apply if one is not provided.") + flag.Parse() // get overrides from environment variables @@ -473,6 +483,11 @@ func main() { WebhookEventTypes: strings.Split(harborWebhookEventTypes, ","), } + buildQoSConfig := controllers.BuildQoS{ + MaxBuilds: qosMaxBuilds, + DefaultValue: qosDefaultValue, + } + podCleanup := handlers.NewCleanup(mgr.GetClient(), buildPodsToKeep, taskPodsToKeep, @@ -538,6 +553,8 @@ func main() { LFFBackupWeeklyRandom: lffBackupWeeklyRandom, LFFHarborEnabled: lffHarborEnabled, Harbor: harborConfig, + LFFQoSEnabled: lffQoSEnabled, + BuildQoS: buildQoSConfig, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "LagoonBuild") os.Exit(1) From 9f026438e9caf6350841d6e491c848526c812c12 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 4 Jun 2021 09:53:15 +1000 Subject: [PATCH 02/35] formatting fixes in main controller --- controllers/lagoonbuild_controller.go | 58 +++++++++++++-------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/controllers/lagoonbuild_controller.go b/controllers/lagoonbuild_controller.go index 29969779..5c30d1a0 100644 --- a/controllers/lagoonbuild_controller.go +++ b/controllers/lagoonbuild_controller.go @@ -93,39 +93,37 @@ func (r *LagoonBuildReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) if r.LFFQoSEnabled { // handle QoS builds here return r.qosBuildProcessor(ctx, opLog, lagoonBuild, req) - } else { - return r.standardBuildProcessor(ctx, opLog, lagoonBuild, req) } - } else { - // The object is being deleted - if containsString(lagoonBuild.ObjectMeta.Finalizers, finalizerName) { - // our finalizer is present, so lets handle any external dependency - // first deleteExternalResources will try and check for any pending builds that it can - // can change to running to kick off the next pending build - if err := r.deleteExternalResources(ctx, - opLog, - &lagoonBuild, - req, - ); err != nil { - // if fail to delete the external dependency here, return with error - // so that it can be retried - opLog.Error(err, fmt.Sprintf("Unable to delete external resources")) - return ctrl.Result{}, err - } - // remove our finalizer from the list and update it. - lagoonBuild.ObjectMeta.Finalizers = removeString(lagoonBuild.ObjectMeta.Finalizers, finalizerName) - // use patches to avoid update errors - mergePatch, _ := json.Marshal(map[string]interface{}{ - "metadata": map[string]interface{}{ - "finalizers": lagoonBuild.ObjectMeta.Finalizers, - }, - }) - if err := r.Patch(ctx, &lagoonBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { - return ctrl.Result{}, ignoreNotFound(err) - } + // if qos is not enabled, just process it as a standard build + return r.standardBuildProcessor(ctx, opLog, lagoonBuild, req) + } + // The object is being deleted + if containsString(lagoonBuild.ObjectMeta.Finalizers, finalizerName) { + // our finalizer is present, so lets handle any external dependency + // first deleteExternalResources will try and check for any pending builds that it can + // can change to running to kick off the next pending build + if err := r.deleteExternalResources(ctx, + opLog, + &lagoonBuild, + req, + ); err != nil { + // if fail to delete the external dependency here, return with error + // so that it can be retried + opLog.Error(err, fmt.Sprintf("Unable to delete external resources")) + return ctrl.Result{}, err + } + // remove our finalizer from the list and update it. + lagoonBuild.ObjectMeta.Finalizers = removeString(lagoonBuild.ObjectMeta.Finalizers, finalizerName) + // use patches to avoid update errors + mergePatch, _ := json.Marshal(map[string]interface{}{ + "metadata": map[string]interface{}{ + "finalizers": lagoonBuild.ObjectMeta.Finalizers, + }, + }) + if err := r.Patch(ctx, &lagoonBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + return ctrl.Result{}, ignoreNotFound(err) } } - return ctrl.Result{}, nil } From 7589356cf4bc2045f02de4d2880701638344b417 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 4 Jun 2021 13:17:56 +1000 Subject: [PATCH 03/35] work on qos --- api/v1alpha1/lagoonbuild_types.go | 13 +- api/v1alpha1/zz_generated.deepcopy.go | 5 + .../bases/lagoon.amazee.io_lagoonbuilds.yaml | 2 + config/default/manager_auth_proxy_patch.yaml | 2 + controller-test.sh | 3 + controllers/lagoonbuild_qoshandler.go | 119 +++++++++++++++++- controllers/lagoonbuild_standardhandler.go | 2 +- 7 files changed, 137 insertions(+), 9 deletions(-) diff --git a/api/v1alpha1/lagoonbuild_types.go b/api/v1alpha1/lagoonbuild_types.go index 7079b4c1..88fc64bc 100644 --- a/api/v1alpha1/lagoonbuild_types.go +++ b/api/v1alpha1/lagoonbuild_types.go @@ -43,12 +43,13 @@ type LagoonBuildSpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "make" to regenerate code after modifying this file - Build Build `json:"build"` - Project Project `json:"project"` - Branch Branch `json:"branch,omitempty"` - Pullrequest Pullrequest `json:"pullrequest,omitempty"` - Promote Promote `json:"promote,omitempty"` - GitReference string `json:"gitReference"` + Build Build `json:"build"` + Project Project `json:"project"` + Branch Branch `json:"branch,omitempty"` + Pullrequest Pullrequest `json:"pullrequest,omitempty"` + Promote Promote `json:"promote,omitempty"` + GitReference string `json:"gitReference"` + BuildPriority *int `json:"buildPriority,omitempty"` // @TODO: Openshift should be deprecated as the controller will define if it is openshift or not // Openshift bool `json:"openshift"` } diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index fca07e94..6f57a1a5 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -140,6 +140,11 @@ func (in *LagoonBuildSpec) DeepCopyInto(out *LagoonBuildSpec) { out.Branch = in.Branch out.Pullrequest = in.Pullrequest out.Promote = in.Promote + if in.BuildPriority != nil { + in, out := &in.BuildPriority, &out.BuildPriority + *out = new(int) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LagoonBuildSpec. diff --git a/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml b/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml index 1caa9f9a..820e77c4 100644 --- a/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml +++ b/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml @@ -53,6 +53,8 @@ spec: required: - type type: object + buildPriority: + type: integer gitReference: type: string project: diff --git a/config/default/manager_auth_proxy_patch.yaml b/config/default/manager_auth_proxy_patch.yaml index 6e9d3195..4e653155 100644 --- a/config/default/manager_auth_proxy_patch.yaml +++ b/config/default/manager_auth_proxy_patch.yaml @@ -29,3 +29,5 @@ spec: - "--harbor-robot-account-expiry=1d" - "--enable-harbor" - "--harbor-enable-project-webhook" + - "--enable-qos" + - "--qos-max-builds=1" diff --git a/controller-test.sh b/controller-test.sh index 32d9010b..ffc118ca 100755 --- a/controller-test.sh +++ b/controller-test.sh @@ -213,6 +213,9 @@ echo "==> Configure example environment" echo "====> Install build deploy controllers" build_deploy_controller +echo "SLEEP" +sleep 1200 + echo "==> Trigger a lagoon build using kubectl apply" kubectl -n $CONTROLLER_NAMESPACE apply -f test-resources/example-project1.yaml # patch the resource with the controller namespace diff --git a/controllers/lagoonbuild_qoshandler.go b/controllers/lagoonbuild_qoshandler.go index d067b23f..765777cb 100644 --- a/controllers/lagoonbuild_qoshandler.go +++ b/controllers/lagoonbuild_qoshandler.go @@ -2,10 +2,15 @@ package controllers import ( "context" + "encoding/json" + "fmt" + "sort" lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" "github.com/go-logr/logr" + "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" ) // BuildQoS is use for the quality of service configuration for lagoon builds. @@ -18,7 +23,117 @@ func (r *LagoonBuildReconciler) qosBuildProcessor(ctx context.Context, opLog logr.Logger, lagoonBuild lagoonv1alpha1.LagoonBuild, req ctrl.Request) (ctrl.Result, error) { - + // check if we get a lagoonbuild that hasn't got any buildstatus + // this means it was created by the message queue handler + // so we should do the steps required for a lagoon build and then copy the build + // into the created namespace + if _, ok := lagoonBuild.ObjectMeta.Labels["lagoon.sh/buildStatus"]; !ok { + return r.createNamespaceBuild(ctx, opLog, lagoonBuild) + } // handle the QoS build process here - return ctrl.Result{}, nil + return ctrl.Result{}, r.whichBuildNext(ctx, opLog) +} + +func (r *LagoonBuildReconciler) whichBuildNext(ctx context.Context, opLog logr.Logger) error { + listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ + client.MatchingLabels(map[string]string{ + "lagoon.sh/buildStatus": "Running", + "lagoon.sh/controller": r.ControllerNamespace, + }), + }) + runningBuilds := &lagoonv1alpha1.LagoonBuildList{} + if err := r.List(ctx, runningBuilds, listOption); err != nil { + return fmt.Errorf("Unable to list builds in the cluster, there may be none or something went wrong: %v", err) + } + opLog.Info(fmt.Sprintf("There are %v Running builds", len(runningBuilds.Items))) + if len(runningBuilds.Items) >= r.BuildQoS.MaxBuilds { + // if the maximum number of builds is hit, then drop out and try again next time + return nil + } + buildsToStart := r.BuildQoS.MaxBuilds - len(runningBuilds.Items) + if buildsToStart > 0 { + opLog.Info(fmt.Sprintf("There is room for %v builds to be started", buildsToStart)) + // if there are any free slots to start a build, do that here + listOption = (&client.ListOptions{}).ApplyOptions([]client.ListOption{ + client.MatchingLabels(map[string]string{ + "lagoon.sh/buildStatus": "Pending", + "lagoon.sh/controller": r.ControllerNamespace, + }), + }) + pendingBuilds := &lagoonv1alpha1.LagoonBuildList{} + if err := r.List(ctx, pendingBuilds, listOption); err != nil { + return fmt.Errorf("Unable to list builds in the cluster, there may be none or something went wrong: %v", err) + } + opLog.Info(fmt.Sprintf("There are %v Pending builds", len(runningBuilds.Items))) + // if we have any pending builds, then grab the latest one and make it running + // if there are any other pending builds, cancel them so only the latest one runs + sort.Slice(pendingBuilds.Items, func(i, j int) bool { + // sort by priority, then creation timestamp + iPriority := r.BuildQoS.DefaultValue + jPriority := r.BuildQoS.DefaultValue + if ok := pendingBuilds.Items[i].Spec.BuildPriority; ok != nil { + iPriority = *pendingBuilds.Items[i].Spec.BuildPriority + } + if ok := pendingBuilds.Items[j].Spec.BuildPriority; ok != nil { + jPriority = *pendingBuilds.Items[j].Spec.BuildPriority + } + if iPriority < jPriority { + return false + } + if iPriority > jPriority { + return true + } + return pendingBuilds.Items[i].ObjectMeta.CreationTimestamp.Before(&pendingBuilds.Items[j].ObjectMeta.CreationTimestamp) + }) + if len(pendingBuilds.Items) > 0 { + for idx, pBuild := range pendingBuilds.Items { + if idx >= buildsToStart { + // if we do have a `lagoon.sh/buildStatus` set, then process as normal + runningNSBuilds := &lagoonv1alpha1.LagoonBuildList{} + listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ + client.InNamespace(pBuild.ObjectMeta.Namespace), + client.MatchingLabels(map[string]string{ + "lagoon.sh/buildStatus": "Running", + "lagoon.sh/controller": r.ControllerNamespace, + }), + }) + // list any builds that are running + if err := r.List(ctx, runningBuilds, listOption); err != nil { + return fmt.Errorf("Unable to list builds in the namespace, there may be none or something went wrong: %v", err) + } + for _, runningBuild := range runningNSBuilds.Items { + // if the running build is the one from this request then process it + if pBuild.ObjectMeta.Name == runningBuild.ObjectMeta.Name { + // actually process the build here + if err := r.processBuild(ctx, opLog, pBuild); err != nil { + return err + } + } // end check if running build is current LagoonBuild + } // end loop for running builds + + // if there are no running builds, check if there are any pending builds that can be started + if len(runningBuilds.Items) == 0 { + pendingNSBuilds := &lagoonv1alpha1.LagoonBuildList{} + return cancelExtraBuilds(ctx, r.Client, opLog, pendingNSBuilds, pBuild.ObjectMeta.Namespace, "Running") + } + // The object is not being deleted, so if it does not have our finalizer, + // then lets add the finalizer and update the object. This is equivalent + // registering our finalizer. + if !containsString(pBuild.ObjectMeta.Finalizers, finalizerName) { + pBuild.ObjectMeta.Finalizers = append(pBuild.ObjectMeta.Finalizers, finalizerName) + // use patches to avoid update errors + mergePatch, _ := json.Marshal(map[string]interface{}{ + "metadata": map[string]interface{}{ + "finalizers": pBuild.ObjectMeta.Finalizers, + }, + }) + if err := r.Patch(ctx, &pBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + return err + } + } + } + } + } + } + return nil } diff --git a/controllers/lagoonbuild_standardhandler.go b/controllers/lagoonbuild_standardhandler.go index 06e850ff..ad353110 100644 --- a/controllers/lagoonbuild_standardhandler.go +++ b/controllers/lagoonbuild_standardhandler.go @@ -47,7 +47,7 @@ func (r *LagoonBuildReconciler) standardBuildProcessor(ctx context.Context, } // end check if running build is current LagoonBuild } // end loop for running builds - // if there are no running builds, check if there are any pending builds + // if there are no running builds, check if there are any pending builds that can be started if len(runningBuilds.Items) == 0 { pendingBuilds := &lagoonv1alpha1.LagoonBuildList{} return ctrl.Result{}, cancelExtraBuilds(ctx, r.Client, opLog, pendingBuilds, req.Namespace, "Running") From 3599305bb9c9f8d0b0c33d4ec28d19769372855e Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 17 Jun 2021 09:16:46 +1000 Subject: [PATCH 04/35] backport regional harbor fixes --- controllers/lagoon_harborintegration.go | 153 +++++++++++++++++++----- controllers/lagoonbuild_helpers.go | 28 +++-- main.go | 9 +- 3 files changed, 151 insertions(+), 39 deletions(-) diff --git a/controllers/lagoon_harborintegration.go b/controllers/lagoon_harborintegration.go index a639946c..99f36fa0 100644 --- a/controllers/lagoon_harborintegration.go +++ b/controllers/lagoon_harborintegration.go @@ -6,6 +6,7 @@ import ( "context" "encoding/base64" + "encoding/json" "time" lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" @@ -15,10 +16,10 @@ import ( "github.com/mittwald/goharbor-client/v3/apiv2/model/legacy" corev1 "k8s.io/api/core/v1" - apierrs "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/selection" + "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -26,6 +27,7 @@ import ( // Harbor defines a harbor struct type Harbor struct { URL string + Hostname string API string Username string Password string @@ -63,11 +65,13 @@ func NewHarbor(harbor Harbor) (*Harbor, error) { func (h *Harbor) CreateProject(ctx context.Context, projectName string) (*model.Project, error) { project, err := h.Client.GetProjectByName(ctx, projectName) if err != nil { - if err.Error() == "project not found on server side" { + if err.Error() == "project not found on server side" || err.Error() == "resource unknown" { project, err = h.Client.NewProject(ctx, projectName, int64Ptr(-1)) if err != nil { + h.Log.Info(fmt.Sprintf("Error creating project %s", projectName)) return nil, err } + time.Sleep(2 * time.Second) // wait 2 seconds tStr := "true" err = h.Client.UpdateProject(ctx, &model.Project{ Name: projectName, @@ -79,14 +83,18 @@ func (h *Harbor) CreateProject(ctx context.Context, projectName string) (*model. }, }, int64Ptr(-1)) if err != nil { + h.Log.Info(fmt.Sprintf("Error updating project %s", projectName)) return nil, err } + time.Sleep(2 * time.Second) // wait 2 seconds project, err = h.Client.GetProjectByName(ctx, projectName) if err != nil { + h.Log.Info(fmt.Sprintf("Error getting project after updating %s", projectName)) return nil, err } - h.Log.Info(fmt.Sprintf("Created harbor project %s", project.Name)) + h.Log.Info(fmt.Sprintf("Created harbor project %s", projectName)) } else { + h.Log.Info(fmt.Sprintf("Error finding project %s", projectName)) return nil, err } } @@ -104,6 +112,7 @@ func (h *Harbor) CreateProject(ctx context.Context, projectName string) (*model. if h.WebhookAddition { wps, err := h.Client.ListProjectWebhookPolicies(ctx, project) if err != nil { + h.Log.Info(fmt.Sprintf("Error listing project %s webhooks", project.Name)) return nil, err } exists := false @@ -127,6 +136,7 @@ func (h *Harbor) CreateProject(ctx context.Context, projectName string) (*model. } err = h.Client.UpdateProjectWebhookPolicy(ctx, project, int(wp.ID), newPolicy) if err != nil { + h.Log.Info(fmt.Sprintf("Error updating project %s webhook", project.Name)) return nil, err } } @@ -148,6 +158,7 @@ func (h *Harbor) CreateProject(ctx context.Context, projectName string) (*model. } err = h.Client.AddProjectWebhookPolicy(ctx, project, newPolicy) if err != nil { + h.Log.Info(fmt.Sprintf("Error adding project %s webhook", project.Name)) return nil, err } } @@ -157,22 +168,67 @@ func (h *Harbor) CreateProject(ctx context.Context, projectName string) (*model. // CreateOrRefreshRobot will create or refresh a robot account and return the credentials if needed. func (h *Harbor) CreateOrRefreshRobot(ctx context.Context, + cl client.Client, project *model.Project, - robotName, namespace, secretName string, + robotName, namespace string, expiry int64, -) (*corev1.Secret, error) { +) (*RegistryCredentials, error) { robots, err := h.Client.ListProjectRobots( ctx, project, ) if err != nil { + h.Log.Info(fmt.Sprintf("Error listing project %s robot accounts", project.Name)) return nil, err } exists := false deleted := false + forceRecreate := false + secret := &corev1.Secret{} + err = cl.Get(ctx, types.NamespacedName{ + Namespace: namespace, + Name: "lagoon-internal-registry-secret", + }, secret) + if err != nil { + // the lagoon registry secret doesn't exist, force re-create the robot account + forceRecreate = true + } + // check if the secret contains the .dockerconfigjson data + if secretData, ok := secret.Data[".dockerconfigjson"]; ok { + auths := Auths{} + // unmarshal it + if err := json.Unmarshal(secretData, &auths); err != nil { + return nil, fmt.Errorf("Could not unmarshal Harbor RobotAccount credential") + } + // set the force recreate robot account flag here + forceRecreate = true + // if the defined regional harbor key exists using the hostname then set the flag to false + // if the account is set to expire, the loop below will catch it for us + // just the hostname, as this is what all new robot accounts are created with + if _, ok := auths.Registries[h.Hostname]; ok { + forceRecreate = false + } + } for _, robot := range robots { if h.matchRobotAccount(robot, project, robotName) { exists = true + if forceRecreate { + // if the secret doesn't exist in kubernetes, then force re-creation of the robot + // account is required, as there isn't a way to get the credentials after + // robot accounts are created + h.Log.Info(fmt.Sprintf("Kubernetes secret doesn't exist, robot account %s needs to be re-created", robot.Name)) + err := h.Client.DeleteProjectRobot( + ctx, + project, + int(robot.ID), + ) + if err != nil { + h.Log.Info(fmt.Sprintf("Error deleting project %s robot account %s", project.Name, robot.Name)) + return nil, err + } + deleted = true + continue + } if robot.Disabled && h.DeleteDisabled { // if accounts are disabled, and deletion of disabled accounts is enabled // then this will delete the account to get re-created @@ -183,6 +239,7 @@ func (h *Harbor) CreateOrRefreshRobot(ctx context.Context, int(robot.ID), ) if err != nil { + h.Log.Info(fmt.Sprintf("Error deleting project %s robot account %s", project.Name, robot.Name)) return nil, err } deleted = true @@ -197,6 +254,7 @@ func (h *Harbor) CreateOrRefreshRobot(ctx context.Context, int(robot.ID), ) if err != nil { + h.Log.Info(fmt.Sprintf("Error deleting project %s robot account %s", project.Name, robot.Name)) return nil, err } deleted = true @@ -211,6 +269,7 @@ func (h *Harbor) CreateOrRefreshRobot(ctx context.Context, int(robot.ID), ) if err != nil { + h.Log.Info(fmt.Sprintf("Error deleting project %s robot account %s", project.Name, robot.Name)) return nil, err } deleted = true @@ -234,20 +293,18 @@ func (h *Harbor) CreateOrRefreshRobot(ctx context.Context, }, ) if err != nil { + h.Log.Info(fmt.Sprintf("Error adding project %s robot account %s", project.Name, robotName)) return nil, err } // then craft and return the harbor credential secret - harborSecret := makeHarborSecret( - namespace, - secretName, - h.URL, + harborRegistryCredentials := makeHarborSecret( robotAccountCredential{ Token: token, Name: h.addPrefix(robotName), }, ) h.Log.Info(fmt.Sprintf("Created robot account %s", h.addPrefix(robotName))) - return &harborSecret, nil + return &harborRegistryCredentials, nil } return nil, err } @@ -257,9 +314,13 @@ func (h *Harbor) RotateRobotCredentials(ctx context.Context, cl client.Client) { opLog := ctrl.Log.WithName("handlers").WithName("RotateRobotCredentials") namespaces := &corev1.NamespaceList{} labelRequirements, _ := labels.NewRequirement("lagoon.sh/environmentType", selection.Exists, nil) + // @TODO: do this later so we can only run robot credentials for specific controllers + // labelRequirements2, _ := labels.NewRequirement("lagoon.sh/controller", selection.Equals, []string{h.ControllerNamespace}) listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ client.MatchingLabelsSelector{ Selector: labels.NewSelector().Add(*labelRequirements), + // @TODO: do this later so we can only run robot credentials for specific controllers + // Selector: labels.NewSelector().Add(*labelRequirements).Add(*labelRequirements2), }, }) if err := cl.List(ctx, namespaces, listOption); err != nil { @@ -275,7 +336,6 @@ func (h *Harbor) RotateRobotCredentials(ctx context.Context, cl client.Client) { listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ client.InNamespace(ns.ObjectMeta.Name), client.MatchingLabels(map[string]string{ - // "lagoon.sh/jobType": "build", "lagoon.sh/controller": h.ControllerNamespace, // created by this controller }), }) @@ -301,19 +361,26 @@ func (h *Harbor) RotateRobotCredentials(ctx context.Context, cl client.Client) { opLog.Error(err, "error getting or creating project") break } + time.Sleep(2 * time.Second) // wait 2 seconds robotCreds, err := h.CreateOrRefreshRobot(ctx, + cl, hProject, ns.Labels["lagoon.sh/environment"], ns.ObjectMeta.Name, - "lagoon-internal-registry-secret", time.Now().Add(h.RobotAccountExpiry).Unix()) if err != nil { opLog.Error(err, "error getting or creating robot account") break } + time.Sleep(2 * time.Second) // wait 2 seconds if robotCreds != nil { // if we have robotcredentials to create, do that here - if err := upsertHarborSecret(ctx, cl, robotCreds); err != nil { + if err := upsertHarborSecret(ctx, + cl, + ns.ObjectMeta.Name, + "lagoon-internal-registry-secret", + h.Hostname, + robotCreds); err != nil { opLog.Error(err, "error creating or updating robot account credentials") break } @@ -368,33 +435,59 @@ func (h *Harbor) expiresSoon(robot *legacy.RobotAccount, duration time.Duration) } // makeHarborSecret creates the secret definition. -func makeHarborSecret(namespace, name string, baseURL string, credentials robotAccountCredential) corev1.Secret { - auth := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", credentials.Name, credentials.Token))) - configJSON := fmt.Sprintf(`{"auths":{"%s":{"username":"%s","password":"%s","auth":"%s"}}}`, baseURL, credentials.Name, credentials.Token, auth) - return corev1.Secret{ +func makeHarborSecret(credentials robotAccountCredential) RegistryCredentials { + return RegistryCredentials{ + Username: credentials.Name, + Password: credentials.Token, + Auth: base64.StdEncoding.EncodeToString( + []byte( + fmt.Sprintf("%s:%s", credentials.Name, credentials.Token), + ), + )} +} + +// upsertHarborSecret will create or update the secret in kubernetes. +func upsertHarborSecret(ctx context.Context, cl client.Client, ns, name, baseURL string, registryCreds *RegistryCredentials) error { + secret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, + Namespace: ns, Name: name, }, Type: corev1.SecretTypeDockerConfigJson, - Data: map[string][]byte{ - corev1.DockerConfigJsonKey: []byte(configJSON), - }, } -} - -// upsertHarborSecret will create or update the secret in kubernetes. -func upsertHarborSecret(ctx context.Context, cl client.Client, secret *corev1.Secret) error { - err := cl.Create(ctx, secret) - if apierrs.IsAlreadyExists(err) { - err = cl.Update(ctx, secret) + err := cl.Get(ctx, types.NamespacedName{ + Namespace: ns, + Name: name, + }, secret) + dcj := &Auths{ + Registries: make(map[string]RegistryCredentials), + } + if err != nil { + // if the secret doesn't exist + // create it + dcj.Registries[baseURL] = *registryCreds + dcjBytes, _ := json.Marshal(dcj) + secret.Data = map[string][]byte{ + corev1.DockerConfigJsonKey: []byte(dcjBytes), + } + err := cl.Create(ctx, secret) if err != nil { - return fmt.Errorf("could not update secret: %s/%s", secret.ObjectMeta.Namespace, secret.ObjectMeta.Name) + return fmt.Errorf("could not create secret %s/%s: %s", secret.ObjectMeta.Namespace, secret.ObjectMeta.Name, err.Error()) } return nil } + // if the secret exists + // update the secret with the new credentials + json.Unmarshal([]byte(secret.Data[corev1.DockerConfigJsonKey]), &dcj) + // add or update the credential + dcj.Registries[baseURL] = *registryCreds + dcjBytes, _ := json.Marshal(dcj) + secret.Data = map[string][]byte{ + corev1.DockerConfigJsonKey: []byte(dcjBytes), + } + err = cl.Update(ctx, secret) if err != nil { - return fmt.Errorf("could not create secret %s/%s: %s", secret.ObjectMeta.Namespace, secret.ObjectMeta.Name, err.Error()) + return fmt.Errorf("could not update secret: %s/%s", secret.ObjectMeta.Namespace, secret.ObjectMeta.Name) } return nil } diff --git a/controllers/lagoonbuild_helpers.go b/controllers/lagoonbuild_helpers.go index 9500caff..9ccd105f 100644 --- a/controllers/lagoonbuild_helpers.go +++ b/controllers/lagoonbuild_helpers.go @@ -135,6 +135,7 @@ func (r *LagoonBuildReconciler) getOrCreateNamespace(ctx context.Context, namesp "lagoon.sh/project": spec.Project.Name, "lagoon.sh/environment": spec.Project.Environment, "lagoon.sh/environmentType": spec.Project.EnvironmentType, + "lagoon.sh/controller": r.ControllerNamespace, } if spec.Project.ID != nil { nsLabels["lagoon.sh/projectId"] = fmt.Sprintf("%d", *spec.Project.ID) @@ -209,17 +210,22 @@ func (r *LagoonBuildReconciler) getOrCreateNamespace(ctx context.Context, namesp } // create or refresh the robot credentials robotCreds, err := lagoonHarbor.CreateOrRefreshRobot(ctx, + r.Client, hProject, spec.Project.Environment, ns, - "lagoon-internal-registry-secret", time.Now().Add(lagoonHarbor.RobotAccountExpiry).Unix()) if err != nil { return err } if robotCreds != nil { // if we have robotcredentials to create, do that here - if err := upsertHarborSecret(ctx, r.Client, robotCreds); err != nil { + if err := upsertHarborSecret(ctx, + r.Client, + ns, + "lagoon-internal-registry-secret", + lagoonHarbor.Hostname, + robotCreds); err != nil { return err } } @@ -637,12 +643,18 @@ func (r *LagoonBuildReconciler) processBuild(ctx context.Context, opLog logr.Log if err := json.Unmarshal(secretData, &auths); err != nil { return fmt.Errorf("Could not unmarshal Harbor RobotAccount credential") } - if len(auths.Registries) == 1 { - for registry, creds := range auths.Registries { - replaceOrAddVariable(lagoonProjectVariables, "INTERNAL_REGISTRY_URL", registry, "internal_container_registry") - replaceOrAddVariable(lagoonProjectVariables, "INTERNAL_REGISTRY_USERNAME", creds.Username, "internal_container_registry") - replaceOrAddVariable(lagoonProjectVariables, "INTERNAL_REGISTRY_PASSWORD", creds.Password, "internal_container_registry") - } + // if the defined regional harbor key exists using the hostname + if creds, ok := auths.Registries[r.Harbor.URL]; ok { + // use the regional harbor in the build + replaceOrAddVariable(lagoonProjectVariables, "INTERNAL_REGISTRY_URL", r.Harbor.URL, "internal_container_registry") + replaceOrAddVariable(lagoonProjectVariables, "INTERNAL_REGISTRY_USERNAME", creds.Username, "internal_container_registry") + replaceOrAddVariable(lagoonProjectVariables, "INTERNAL_REGISTRY_PASSWORD", creds.Password, "internal_container_registry") + } + if creds, ok := auths.Registries[r.Harbor.Hostname]; ok { + // use the regional harbor in the build + replaceOrAddVariable(lagoonProjectVariables, "INTERNAL_REGISTRY_URL", r.Harbor.Hostname, "internal_container_registry") + replaceOrAddVariable(lagoonProjectVariables, "INTERNAL_REGISTRY_USERNAME", creds.Username, "internal_container_registry") + replaceOrAddVariable(lagoonProjectVariables, "INTERNAL_REGISTRY_PASSWORD", creds.Password, "internal_container_registry") } } // marshal any changes into the project spec on the fly, don't save the spec though diff --git a/main.go b/main.go index 303b1b18..79551dbb 100644 --- a/main.go +++ b/main.go @@ -19,6 +19,7 @@ import ( "context" "flag" "fmt" + "net/url" "os" "strconv" "strings" @@ -202,7 +203,7 @@ func main() { // harbor configurations flag.BoolVar(&lffHarborEnabled, "enable-harbor", false, "Flag to enable this controller to talk to a specific harbor.") - flag.StringVar(&harborURL, "harbor-url", "http://harbor.172.17.0.1.nip.io:32080", + flag.StringVar(&harborURL, "harbor-url", "harbor.172.17.0.1.nip.io:32080", "The URL for harbor, this is where images will be pushed.") flag.StringVar(&harborAPI, "harbor-api", "http://harbor.172.17.0.1.nip.io:32080/api/", "The URL for harbor API.") @@ -467,8 +468,14 @@ func main() { }) } + harborURLParsed, _ := url.Parse(harborURL) + harborHostname := harborURLParsed.Host + if harborURLParsed.Host == "" { + harborHostname = harborURL + } harborConfig := controllers.Harbor{ URL: harborURL, + Hostname: harborHostname, API: harborAPI, Username: harborUsername, Password: harborPassword, From 11870f6d36b56f6da3a3c3a307feb8535e00ec80 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 17 Jun 2021 15:57:28 +1000 Subject: [PATCH 05/35] process builds --- controller-test.sh | 4 ++-- controllers/lagoonbuild_controller.go | 23 +++++++++++++++++++++++ controllers/lagoonbuild_qoshandler.go | 16 +++------------- 3 files changed, 28 insertions(+), 15 deletions(-) diff --git a/controller-test.sh b/controller-test.sh index ffc118ca..b5cef773 100755 --- a/controller-test.sh +++ b/controller-test.sh @@ -213,8 +213,8 @@ echo "==> Configure example environment" echo "====> Install build deploy controllers" build_deploy_controller -echo "SLEEP" -sleep 1200 +# echo "SLEEP" +# sleep 1200 echo "==> Trigger a lagoon build using kubectl apply" kubectl -n $CONTROLLER_NAMESPACE apply -f test-resources/example-project1.yaml diff --git a/controllers/lagoonbuild_controller.go b/controllers/lagoonbuild_controller.go index 5c30d1a0..0c0159d9 100644 --- a/controllers/lagoonbuild_controller.go +++ b/controllers/lagoonbuild_controller.go @@ -92,6 +92,29 @@ func (r *LagoonBuildReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) if lagoonBuild.ObjectMeta.DeletionTimestamp.IsZero() { if r.LFFQoSEnabled { // handle QoS builds here + // if we do have a `lagoon.sh/buildStatus` set as running, then process it + runningNSBuilds := &lagoonv1alpha1.LagoonBuildList{} + listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ + client.InNamespace(req.Namespace), + client.MatchingLabels(map[string]string{ + "lagoon.sh/buildStatus": "Running", + "lagoon.sh/controller": r.ControllerNamespace, + }), + }) + // list any builds that are running + if err := r.List(ctx, runningNSBuilds, listOption); err != nil { + return ctrl.Result{}, fmt.Errorf("Unable to list builds in the namespace, there may be none or something went wrong: %v", err) + } + for _, runningBuild := range runningNSBuilds.Items { + // if the running build is the one from this request then process it + if lagoonBuild.ObjectMeta.Name == runningBuild.ObjectMeta.Name { + // actually process the build here + if err := r.processBuild(ctx, opLog, lagoonBuild); err != nil { + return ctrl.Result{}, err + } + } // end check if running build is current LagoonBuild + } // end loop for running builds + // once running builds are processed, run the qos handler return r.qosBuildProcessor(ctx, opLog, lagoonBuild, req) } // if qos is not enabled, just process it as a standard build diff --git a/controllers/lagoonbuild_qoshandler.go b/controllers/lagoonbuild_qoshandler.go index 765777cb..d8fd0e22 100644 --- a/controllers/lagoonbuild_qoshandler.go +++ b/controllers/lagoonbuild_qoshandler.go @@ -87,7 +87,7 @@ func (r *LagoonBuildReconciler) whichBuildNext(ctx context.Context, opLog logr.L }) if len(pendingBuilds.Items) > 0 { for idx, pBuild := range pendingBuilds.Items { - if idx >= buildsToStart { + if idx <= buildsToStart { // if we do have a `lagoon.sh/buildStatus` set, then process as normal runningNSBuilds := &lagoonv1alpha1.LagoonBuildList{} listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ @@ -98,21 +98,11 @@ func (r *LagoonBuildReconciler) whichBuildNext(ctx context.Context, opLog logr.L }), }) // list any builds that are running - if err := r.List(ctx, runningBuilds, listOption); err != nil { + if err := r.List(ctx, runningNSBuilds, listOption); err != nil { return fmt.Errorf("Unable to list builds in the namespace, there may be none or something went wrong: %v", err) } - for _, runningBuild := range runningNSBuilds.Items { - // if the running build is the one from this request then process it - if pBuild.ObjectMeta.Name == runningBuild.ObjectMeta.Name { - // actually process the build here - if err := r.processBuild(ctx, opLog, pBuild); err != nil { - return err - } - } // end check if running build is current LagoonBuild - } // end loop for running builds - // if there are no running builds, check if there are any pending builds that can be started - if len(runningBuilds.Items) == 0 { + if len(runningNSBuilds.Items) == 0 { pendingNSBuilds := &lagoonv1alpha1.LagoonBuildList{} return cancelExtraBuilds(ctx, r.Client, opLog, pendingNSBuilds, pBuild.ObjectMeta.Namespace, "Running") } From 1261d650a4f7a1f7e2adc46894d58f81b5e1a6ac Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 18 Jun 2021 10:27:05 +1000 Subject: [PATCH 06/35] minor tweaks --- config/default/manager_auth_proxy_patch.yaml | 2 +- controllers/lagoon_harborintegration.go | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/config/default/manager_auth_proxy_patch.yaml b/config/default/manager_auth_proxy_patch.yaml index 4e653155..d475d7b3 100644 --- a/config/default/manager_auth_proxy_patch.yaml +++ b/config/default/manager_auth_proxy_patch.yaml @@ -30,4 +30,4 @@ spec: - "--enable-harbor" - "--harbor-enable-project-webhook" - "--enable-qos" - - "--qos-max-builds=1" + - "--qos-max-builds=3" diff --git a/controllers/lagoon_harborintegration.go b/controllers/lagoon_harborintegration.go index bcf43079..1cc59823 100644 --- a/controllers/lagoon_harborintegration.go +++ b/controllers/lagoon_harborintegration.go @@ -71,7 +71,7 @@ func (h *Harbor) CreateProject(ctx context.Context, projectName string) (*model. h.Log.Info(fmt.Sprintf("Error creating project %s", projectName)) return nil, err } - time.Sleep(2 * time.Second) // wait 2 seconds + time.Sleep(1 * time.Second) // wait 1 seconds tStr := "true" err = h.Client.UpdateProject(ctx, &model.Project{ Name: projectName, @@ -86,7 +86,7 @@ func (h *Harbor) CreateProject(ctx context.Context, projectName string) (*model. h.Log.Info(fmt.Sprintf("Error updating project %s", projectName)) return nil, err } - time.Sleep(2 * time.Second) // wait 2 seconds + time.Sleep(1 * time.Second) // wait 1 seconds project, err = h.Client.GetProjectByName(ctx, projectName) if err != nil { h.Log.Info(fmt.Sprintf("Error getting project after updating %s", projectName)) @@ -362,7 +362,7 @@ func (h *Harbor) RotateRobotCredentials(ctx context.Context, cl client.Client) { opLog.Error(err, "error getting or creating project") break } - time.Sleep(2 * time.Second) // wait 2 seconds + time.Sleep(1 * time.Second) // wait 1 seconds robotCreds, err := h.CreateOrRefreshRobot(ctx, cl, hProject, @@ -373,7 +373,7 @@ func (h *Harbor) RotateRobotCredentials(ctx context.Context, cl client.Client) { opLog.Error(err, "error getting or creating robot account") break } - time.Sleep(2 * time.Second) // wait 2 seconds + time.Sleep(1 * time.Second) // wait 1 seconds if robotCreds != nil { // if we have robotcredentials to create, do that here if err := upsertHarborSecret(ctx, From 480bd4d3c93369301bc986c6d8e631ffff01c301 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Mon, 21 Jun 2021 15:41:52 +1000 Subject: [PATCH 07/35] move build priority into build section --- api/v1alpha1/lagoonbuild_types.go | 20 +++++++++---------- api/v1alpha1/zz_generated.deepcopy.go | 12 +++++------ .../bases/lagoon.amazee.io_lagoonbuilds.yaml | 4 ++-- controllers/lagoonbuild_qoshandler.go | 8 ++++---- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/api/v1alpha1/lagoonbuild_types.go b/api/v1alpha1/lagoonbuild_types.go index 88fc64bc..e827a49a 100644 --- a/api/v1alpha1/lagoonbuild_types.go +++ b/api/v1alpha1/lagoonbuild_types.go @@ -43,13 +43,12 @@ type LagoonBuildSpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster // Important: Run "make" to regenerate code after modifying this file - Build Build `json:"build"` - Project Project `json:"project"` - Branch Branch `json:"branch,omitempty"` - Pullrequest Pullrequest `json:"pullrequest,omitempty"` - Promote Promote `json:"promote,omitempty"` - GitReference string `json:"gitReference"` - BuildPriority *int `json:"buildPriority,omitempty"` + Build Build `json:"build"` + Project Project `json:"project"` + Branch Branch `json:"branch,omitempty"` + Pullrequest Pullrequest `json:"pullrequest,omitempty"` + Promote Promote `json:"promote,omitempty"` + GitReference string `json:"gitReference"` // @TODO: Openshift should be deprecated as the controller will define if it is openshift or not // Openshift bool `json:"openshift"` } @@ -97,9 +96,10 @@ func init() { // Build contains the type of build, and the image to use for the builder. type Build struct { - CI string `json:"ci,omitempty"` - Image string `json:"image,omitempty"` - Type string `json:"type"` + CI string `json:"ci,omitempty"` + Image string `json:"image,omitempty"` + Type string `json:"type"` + Priority *int `json:"priority,omitempty"` } // Project contains the project information from lagoon. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 6f57a1a5..f55cb0fd 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -41,6 +41,11 @@ func (in *Branch) DeepCopy() *Branch { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Build) DeepCopyInto(out *Build) { *out = *in + if in.Priority != nil { + in, out := &in.Priority, &out.Priority + *out = new(int) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Build. @@ -135,16 +140,11 @@ func (in *LagoonBuildList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LagoonBuildSpec) DeepCopyInto(out *LagoonBuildSpec) { *out = *in - out.Build = in.Build + in.Build.DeepCopyInto(&out.Build) in.Project.DeepCopyInto(&out.Project) out.Branch = in.Branch out.Pullrequest = in.Pullrequest out.Promote = in.Promote - if in.BuildPriority != nil { - in, out := &in.BuildPriority, &out.BuildPriority - *out = new(int) - **out = **in - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LagoonBuildSpec. diff --git a/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml b/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml index 820e77c4..3c7e22d0 100644 --- a/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml +++ b/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml @@ -48,13 +48,13 @@ spec: type: string image: type: string + priority: + type: integer type: type: string required: - type type: object - buildPriority: - type: integer gitReference: type: string project: diff --git a/controllers/lagoonbuild_qoshandler.go b/controllers/lagoonbuild_qoshandler.go index d8fd0e22..182a399d 100644 --- a/controllers/lagoonbuild_qoshandler.go +++ b/controllers/lagoonbuild_qoshandler.go @@ -71,11 +71,11 @@ func (r *LagoonBuildReconciler) whichBuildNext(ctx context.Context, opLog logr.L // sort by priority, then creation timestamp iPriority := r.BuildQoS.DefaultValue jPriority := r.BuildQoS.DefaultValue - if ok := pendingBuilds.Items[i].Spec.BuildPriority; ok != nil { - iPriority = *pendingBuilds.Items[i].Spec.BuildPriority + if ok := pendingBuilds.Items[i].Spec.Build.Priority; ok != nil { + iPriority = *pendingBuilds.Items[i].Spec.Build.Priority } - if ok := pendingBuilds.Items[j].Spec.BuildPriority; ok != nil { - jPriority = *pendingBuilds.Items[j].Spec.BuildPriority + if ok := pendingBuilds.Items[j].Spec.Build.Priority; ok != nil { + jPriority = *pendingBuilds.Items[j].Spec.Build.Priority } if iPriority < jPriority { return false From 092ad61f154cf5e3affcb81b069a71ede29e7a80 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 7 Jul 2021 13:12:50 +1000 Subject: [PATCH 08/35] add bulk id --- api/v1alpha1/lagoonbuild_types.go | 1 + 1 file changed, 1 insertion(+) diff --git a/api/v1alpha1/lagoonbuild_types.go b/api/v1alpha1/lagoonbuild_types.go index e827a49a..537e1c18 100644 --- a/api/v1alpha1/lagoonbuild_types.go +++ b/api/v1alpha1/lagoonbuild_types.go @@ -100,6 +100,7 @@ type Build struct { Image string `json:"image,omitempty"` Type string `json:"type"` Priority *int `json:"priority,omitempty"` + BulkID string `json:"bulkId,omitempty"` } // Project contains the project information from lagoon. From 0bc64d70231355e33de865a802bd5f1364bdddec Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 7 Jul 2021 13:13:30 +1000 Subject: [PATCH 09/35] fix some flag help text and rabbit intervals --- handlers/message_queue.go | 2 +- main.go | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/handlers/message_queue.go b/handlers/message_queue.go index 9f5117da..e485fea0 100644 --- a/handlers/message_queue.go +++ b/handlers/message_queue.go @@ -75,7 +75,7 @@ func (h *Messaging) Consumer(targetName string) { //error { h.ConnectionAttempts, ), ) - time.Sleep(60 * time.Second) + time.Sleep(time.Duration(h.ConnectionRetryInterval) * time.Second) } return attempt < h.ConnectionAttempts, err }) diff --git a/main.go b/main.go index f33d702d..f985d59b 100644 --- a/main.go +++ b/main.go @@ -136,17 +136,17 @@ func main() { flag.StringVar(&mqHost, "rabbitmq-hostname", "localhost:5672", "The hostname:port for the rabbitmq host.") flag.IntVar(&mqWorkers, "rabbitmq-queue-workers", 1, - "The hostname:port for the rabbitmq host.") + "The number of workers to start with.") flag.IntVar(&rabbitRetryInterval, "rabbitmq-retry-interval", 30, - "The hostname:port for the rabbitmq host.") + "The retry interval for rabbitmq.") flag.StringVar(&leaderElectionID, "leader-election-id", "lagoon-builddeploy-leader-election-helper", "The ID to use for leader election.") flag.StringVar(&pendingMessageCron, "pending-message-cron", "*/5 * * * *", - "The hostname:port for the rabbitmq host.") + "The cron definition for pending messages.") flag.IntVar(&startupConnectionAttempts, "startup-connection-attempts", 10, - "The hostname:port for the rabbitmq host.") + "The number of startup attempts before exiting.") flag.IntVar(&startupConnectionInterval, "startup-connection-interval-seconds", 30, - "The hostname:port for the rabbitmq host.") + "The duration between startup attempts.") flag.BoolVar(&enableLeaderElection, "enable-leader-election", false, "Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.") flag.BoolVar(&enableMQ, "enable-message-queue", true, From e53e6e32ecc06527573ccad98004af5f571bdc5b Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 9 Jul 2021 16:46:19 +1000 Subject: [PATCH 10/35] merge main and fix location of changes --- controllers/lagoonbuild_controller.go | 593 -------------------------- 1 file changed, 593 deletions(-) diff --git a/controllers/lagoonbuild_controller.go b/controllers/lagoonbuild_controller.go index c145dc15..93d4013d 100644 --- a/controllers/lagoonbuild_controller.go +++ b/controllers/lagoonbuild_controller.go @@ -92,604 +92,11 @@ func (r *LagoonBuildReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) // examine DeletionTimestamp to determine if object is under deletion if lagoonBuild.ObjectMeta.DeletionTimestamp.IsZero() { -<<<<<<< HEAD if r.LFFQoSEnabled { // handle QoS builds here // if we do have a `lagoon.sh/buildStatus` set as running, then process it runningNSBuilds := &lagoonv1alpha1.LagoonBuildList{} listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ -======= - // check if we get a lagoonbuild that hasn't got any buildstatus - // this means it was created by the message queue handler - // so we should do the steps required for a lagoon build and then copy the build - // into the created namespace - if _, ok := lagoonBuild.ObjectMeta.Labels["lagoon.sh/buildStatus"]; !ok { - // Namesapce creation - namespace := &corev1.Namespace{} - opLog.Info(fmt.Sprintf("Checking Namespace exists for: %s", lagoonBuild.ObjectMeta.Name)) - err := r.getOrCreateNamespace(ctx, namespace, lagoonBuild.Spec) - if err != nil { - return ctrl.Result{}, err - } - // create the `lagoon-deployer` ServiceAccount - opLog.Info(fmt.Sprintf("Checking `lagoon-deployer` ServiceAccount exists: %s", lagoonBuild.ObjectMeta.Name)) - serviceAccount := &corev1.ServiceAccount{} - err = r.getOrCreateServiceAccount(ctx, serviceAccount, namespace.ObjectMeta.Name) - if err != nil { - return ctrl.Result{}, err - } - // ServiceAccount RoleBinding creation - opLog.Info(fmt.Sprintf("Checking `lagoon-deployer-admin` RoleBinding exists: %s", lagoonBuild.ObjectMeta.Name)) - saRoleBinding := &rbacv1.RoleBinding{} - err = r.getOrCreateSARoleBinding(ctx, saRoleBinding, namespace.ObjectMeta.Name) - if err != nil { - return ctrl.Result{}, err - } - - if r.IsOpenshift && lagoonBuild.Spec.Build.Type == "promote" { - err := r.getOrCreatePromoteSARoleBinding(ctx, lagoonBuild.Spec.Promote.SourceProject, namespace.ObjectMeta.Name) - if err != nil { - return ctrl.Result{}, err - } - } - - // copy the build resource into a new resource and set the status to pending - // create the new resource and the controller will handle it via queue - opLog.Info(fmt.Sprintf("Creating LagoonBuild in Pending status: %s", lagoonBuild.ObjectMeta.Name)) - err = r.getOrCreateBuildResource(ctx, &lagoonBuild, namespace.ObjectMeta.Name) - if err != nil { - return ctrl.Result{}, err - } - // if everything is all good controller will handle the new build resource that gets created as it will have - // the `lagoon.sh/buildStatus = Pending` now - // so end this reconcile process - return ctrl.Result{}, nil - } - // if we do have a `lagoon.sh/buildStatus` set, then process as normal - runningBuilds := &lagoonv1alpha1.LagoonBuildList{} - listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ - client.InNamespace(req.Namespace), - client.MatchingLabels(map[string]string{ - "lagoon.sh/buildStatus": "Running", - "lagoon.sh/controller": r.ControllerNamespace, - }), - }) - // list any builds that are running - if err := r.List(ctx, runningBuilds, listOption); err != nil { - return ctrl.Result{}, fmt.Errorf("Unable to list builds in the namespace, there may be none or something went wrong: %v", err) - } - for _, runningBuild := range runningBuilds.Items { - // if the running build is the one from this request then process it - if lagoonBuild.ObjectMeta.Name == runningBuild.ObjectMeta.Name { - // we run these steps again just to be sure that it gets updated/created if it hasn't already - opLog.Info(fmt.Sprintf("Starting work on build: %s", lagoonBuild.ObjectMeta.Name)) - // create the lagoon-sshkey secret - sshKey := &corev1.Secret{} - opLog.Info(fmt.Sprintf("Checking `lagoon-sshkey` Secret exists: %s", lagoonBuild.ObjectMeta.Name)) - err := r.getCreateOrUpdateSSHKeySecret(ctx, sshKey, lagoonBuild.Spec, lagoonBuild.ObjectMeta.Namespace) - if err != nil { - return ctrl.Result{}, err - } - - // create the `lagoon-deployer` ServiceAccount - opLog.Info(fmt.Sprintf("Checking `lagoon-deployer` ServiceAccount exists: %s", lagoonBuild.ObjectMeta.Name)) - serviceAccount := &corev1.ServiceAccount{} - err = r.getOrCreateServiceAccount(ctx, serviceAccount, lagoonBuild.ObjectMeta.Namespace) - if err != nil { - return ctrl.Result{}, err - } - - // ServiceAccount RoleBinding creation - opLog.Info(fmt.Sprintf("Checking `lagoon-deployer-admin` RoleBinding exists: %s", lagoonBuild.ObjectMeta.Name)) - saRoleBinding := &rbacv1.RoleBinding{} - err = r.getOrCreateSARoleBinding(ctx, saRoleBinding, lagoonBuild.ObjectMeta.Namespace) - if err != nil { - return ctrl.Result{}, err - } - - if r.IsOpenshift && lagoonBuild.Spec.Build.Type == "promote" { - err := r.getOrCreatePromoteSARoleBinding(ctx, lagoonBuild.Spec.Promote.SourceProject, lagoonBuild.ObjectMeta.Namespace) - if err != nil { - return ctrl.Result{}, err - } - } - - opLog.Info(fmt.Sprintf("Checking `lagoon-deployer` Token exists: %s", lagoonBuild.ObjectMeta.Name)) - var serviceaccountTokenSecret string - for _, secret := range serviceAccount.Secrets { - match, _ := regexp.MatchString("^lagoon-deployer-token", secret.Name) - if match { - serviceaccountTokenSecret = secret.Name - break - } - } - if serviceaccountTokenSecret == "" { - return ctrl.Result{}, fmt.Errorf("Could not find token secret for ServiceAccount lagoon-deployer") - } - - // openshift uses a builder service account to be able to push images to the openshift registry - // lets load this in exactly the same way an openshift build would - var builderServiceaccountTokenSecret string - if r.IsOpenshift { - builderAccount := &corev1.ServiceAccount{} - err := r.Get(ctx, types.NamespacedName{ - Namespace: lagoonBuild.ObjectMeta.Namespace, - Name: "builder", - }, builderAccount) - if err != nil { - return ctrl.Result{}, fmt.Errorf("Could not find ServiceAccount builder") - } - opLog.Info(fmt.Sprintf("Checking `builder` Token exists: %s", lagoonBuild.ObjectMeta.Name)) - for _, secret := range builderAccount.Secrets { - match, _ := regexp.MatchString("^builder-token", secret.Name) - if match { - builderServiceaccountTokenSecret = secret.Name - break - } - } - if builderServiceaccountTokenSecret == "" { - return ctrl.Result{}, fmt.Errorf("Could not find token secret for ServiceAccount builder") - } - } - - // create the Pod that will do the work - podEnvs := []corev1.EnvVar{ - { - Name: "SOURCE_REPOSITORY", - Value: lagoonBuild.Spec.Project.GitURL, - }, - { - Name: "GIT_REF", - Value: lagoonBuild.Spec.GitReference, - }, - { - Name: "SUBFOLDER", - Value: lagoonBuild.Spec.Project.SubFolder, - }, - { - Name: "BRANCH", - Value: lagoonBuild.Spec.Branch.Name, - }, - { - Name: "PROJECT", - Value: lagoonBuild.Spec.Project.Name, - }, - { - Name: "ENVIRONMENT_TYPE", - Value: lagoonBuild.Spec.Project.EnvironmentType, - }, - { - Name: "ACTIVE_ENVIRONMENT", - Value: lagoonBuild.Spec.Project.ProductionEnvironment, - }, - { - Name: "STANDBY_ENVIRONMENT", - Value: lagoonBuild.Spec.Project.StandbyEnvironment, - }, - { - Name: "PROJECT_SECRET", - Value: lagoonBuild.Spec.Project.ProjectSecret, - }, - { - Name: "MONITORING_ALERTCONTACT", - Value: lagoonBuild.Spec.Project.Monitoring.Contact, - }, - { - Name: "DEFAULT_BACKUP_SCHEDULE", - Value: r.BackupDefaultSchedule, - }, - { - Name: "MONTHLY_BACKUP_DEFAULT_RETENTION", - Value: strconv.Itoa(r.BackupDefaultMonthlyRetention), - }, - { - Name: "WEEKLY_BACKUP_DEFAULT_RETENTION", - Value: strconv.Itoa(r.BackupDefaultWeeklyRetention), - }, - { - Name: "DAILY_BACKUP_DEFAULT_RETENTION", - Value: strconv.Itoa(r.BackupDefaultDailyRetention), - }, - { - Name: "HOURLY_BACKUP_DEFAULT_RETENTION", - Value: strconv.Itoa(r.BackupDefaultHourlyRetention), - }, - { - Name: "K8UP_WEEKLY_RANDOM_FEATURE_FLAG", - Value: strconv.FormatBool(r.LFFBackupWeeklyRandom), - }, - } - if r.IsOpenshift { - // openshift builds have different names for some things, and also additional values to add - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "TYPE", - Value: lagoonBuild.Spec.Build.Type, - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "SAFE_BRANCH", - Value: lagoonBuild.Spec.Project.Environment, - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "SAFE_PROJECT", - Value: makeSafe(lagoonBuild.Spec.Project.Name), - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "OPENSHIFT_NAME", - Value: lagoonBuild.Spec.Project.DeployTarget, - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "ROUTER_URL", - Value: strings.ToLower( - strings.Replace( - strings.Replace( - lagoonBuild.Spec.Project.RouterPattern, - "${branch}", - lagoonBuild.Spec.Project.Environment, - -1, - ), - "${project}", - lagoonBuild.Spec.Project.Name, - -1, - ), - ), - }) - } else { - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "BUILD_TYPE", - Value: lagoonBuild.Spec.Build.Type, - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "ENVIRONMENT", - Value: lagoonBuild.Spec.Project.Environment, - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "KUBERNETES", - Value: lagoonBuild.Spec.Project.DeployTarget, - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "REGISTRY", - Value: lagoonBuild.Spec.Project.Registry, - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "ROUTER_URL", - Value: strings.ToLower( - strings.Replace( - strings.Replace( - lagoonBuild.Spec.Project.RouterPattern, - "${environment}", - lagoonBuild.Spec.Project.Environment, - -1, - ), - "${project}", - lagoonBuild.Spec.Project.Name, - -1, - ), - ), - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "SHORT_ROUTER_URL", - Value: strings.ToLower( - strings.Replace( - strings.Replace( - lagoonBuild.Spec.Project.RouterPattern, - "${environment}", - shortName(lagoonBuild.Spec.Project.Environment), - -1, - ), - "${project}", - shortName(lagoonBuild.Spec.Project.Name), - -1, - ), - ), - }) - } - if lagoonBuild.Spec.Build.CI != "" { - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "CI", - Value: lagoonBuild.Spec.Build.CI, - }) - } - if lagoonBuild.Spec.Build.Type == "pullrequest" { - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "PR_HEAD_BRANCH", - Value: lagoonBuild.Spec.Pullrequest.HeadBranch, - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "PR_HEAD_SHA", - Value: lagoonBuild.Spec.Pullrequest.HeadSha, - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "PR_BASE_BRANCH", - Value: lagoonBuild.Spec.Pullrequest.BaseBranch, - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "PR_BASE_SHA", - Value: lagoonBuild.Spec.Pullrequest.BaseSha, - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "PR_TITLE", - Value: lagoonBuild.Spec.Pullrequest.Title, - }) - if !r.IsOpenshift { - // we don't use PR_NUMBER in openshift builds - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "PR_NUMBER", - Value: string(lagoonBuild.Spec.Pullrequest.Number), - }) - } - } - if lagoonBuild.Spec.Build.Type == "promote" { - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "PROMOTION_SOURCE_ENVIRONMENT", - Value: lagoonBuild.Spec.Promote.SourceEnvironment, - }) - if r.IsOpenshift { - // openshift does promotions differently - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "PROMOTION_SOURCE_OPENSHIFT_PROJECT", - Value: lagoonBuild.Spec.Promote.SourceProject, - }) - } - } - // if local/regional harbor is enabled, and this is not an openshift 3 cluster - if r.LFFHarborEnabled && !r.IsOpenshift { - // unmarshal the project variables - lagoonProjectVariables := &[]LagoonEnvironmentVariable{} - lagoonEnvironmentVariables := &[]LagoonEnvironmentVariable{} - json.Unmarshal(lagoonBuild.Spec.Project.Variables.Project, lagoonProjectVariables) - json.Unmarshal(lagoonBuild.Spec.Project.Variables.Environment, lagoonEnvironmentVariables) - // check if INTERNAL_REGISTRY_SOURCE_LAGOON is defined, and if it isn't true - // if this value is true, then we want to use what is provided by Lagoon - // if it is false, or not set, then we use what is provided by this controller - // this allows us to make it so a specific environment or the project entirely - // can still use whats provided by lagoon - if !variableExists(lagoonProjectVariables, "INTERNAL_REGISTRY_SOURCE_LAGOON", "true") || - !variableExists(lagoonEnvironmentVariables, "INTERNAL_REGISTRY_SOURCE_LAGOON", "true") { - // source the robot credential, and inject it into the lagoon project variables - // this will overwrite what is provided by lagoon (if lagoon has provided them) - // or it will add them. - robotCredential := &corev1.Secret{} - if err = r.Get(ctx, types.NamespacedName{ - Namespace: lagoonBuild.ObjectMeta.Namespace, - Name: "lagoon-internal-registry-secret", - }, robotCredential); err != nil { - return ctrl.Result{}, fmt.Errorf("Could not find Harbor RobotAccount credential") - } - auths := Auths{} - if secretData, ok := robotCredential.Data[".dockerconfigjson"]; ok { - if err := json.Unmarshal(secretData, &auths); err != nil { - return ctrl.Result{}, fmt.Errorf("Could not unmarshal Harbor RobotAccount credential") - } - // if the defined regional harbor key exists using the hostname - if creds, ok := auths.Registries[r.Harbor.URL]; ok { - // use the regional harbor in the build - replaceOrAddVariable(lagoonProjectVariables, "INTERNAL_REGISTRY_URL", r.Harbor.URL, "internal_container_registry") - replaceOrAddVariable(lagoonProjectVariables, "INTERNAL_REGISTRY_USERNAME", creds.Username, "internal_container_registry") - replaceOrAddVariable(lagoonProjectVariables, "INTERNAL_REGISTRY_PASSWORD", creds.Password, "internal_container_registry") - } - if creds, ok := auths.Registries[r.Harbor.Hostname]; ok { - // use the regional harbor in the build - replaceOrAddVariable(lagoonProjectVariables, "INTERNAL_REGISTRY_URL", r.Harbor.Hostname, "internal_container_registry") - replaceOrAddVariable(lagoonProjectVariables, "INTERNAL_REGISTRY_USERNAME", creds.Username, "internal_container_registry") - replaceOrAddVariable(lagoonProjectVariables, "INTERNAL_REGISTRY_PASSWORD", creds.Password, "internal_container_registry") - } - } - // marshal any changes into the project spec on the fly, don't save the spec though - // these values are being overwritten and injected directly into the build pod to be consumed - // by the build pod image - lagoonBuild.Spec.Project.Variables.Project, _ = json.Marshal(lagoonProjectVariables) - } - } - if lagoonBuild.Spec.Project.Variables.Project != nil { - // if this is 2 bytes long, then it means its just an empty json array - // we only want to add it if it is more than 2 bytes - if len(lagoonBuild.Spec.Project.Variables.Project) > 2 { - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "LAGOON_PROJECT_VARIABLES", - Value: string(lagoonBuild.Spec.Project.Variables.Project), - }) - } - } - if lagoonBuild.Spec.Project.Variables.Environment != nil { - // if this is 2 bytes long, then it means its just an empty json array - // we only want to add it if it is more than 2 bytes - if len(lagoonBuild.Spec.Project.Variables.Environment) > 2 { - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "LAGOON_ENVIRONMENT_VARIABLES", - Value: string(lagoonBuild.Spec.Project.Variables.Environment), - }) - } - } - if lagoonBuild.Spec.Project.Monitoring.StatuspageID != "" { - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "MONITORING_STATUSPAGEID", - Value: lagoonBuild.Spec.Project.Monitoring.StatuspageID, - }) - } - // if the fastly watch status is set on the controller, inject the fastly service ID into the build pod to be consumed - // by the build-depoy-dind image - if r.FastlyWatchStatus { - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "LAGOON_FASTLY_NOCACHE_SERVICE_ID", - Value: r.FastlyServiceID, - }) - } - // Set any defined Lagoon feature flags in the build environment. - if r.LFFForceRootlessWorkload != "" { - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "LAGOON_FEATURE_FLAG_FORCE_ROOTLESS_WORKLOAD", - Value: r.LFFForceRootlessWorkload, - }) - } - if r.LFFDefaultRootlessWorkload != "" { - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "LAGOON_FEATURE_FLAG_DEFAULT_ROOTLESS_WORKLOAD", - Value: r.LFFDefaultRootlessWorkload, - }) - } - if r.LFFForceIsolationNetworkPolicy != "" { - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "LAGOON_FEATURE_FLAG_FORCE_ISOLATION_NETWORK_POLICY", - Value: r.LFFForceIsolationNetworkPolicy, - }) - } - if r.LFFDefaultIsolationNetworkPolicy != "" { - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "LAGOON_FEATURE_FLAG_DEFAULT_ISOLATION_NETWORK_POLICY", - Value: r.LFFDefaultIsolationNetworkPolicy, - }) - } - // Use the build image in the controller definition - buildImage := r.BuildImage - if lagoonBuild.Spec.Build.Image != "" { - // otherwise if the build spec contains an image definition, use it instead. - buildImage = lagoonBuild.Spec.Build.Image - } - newPod := &corev1.Pod{ - ObjectMeta: metav1.ObjectMeta{ - Name: lagoonBuild.ObjectMeta.Name, - Namespace: lagoonBuild.ObjectMeta.Namespace, - Labels: map[string]string{ - "lagoon.sh/jobType": "build", - "lagoon.sh/buildName": lagoonBuild.ObjectMeta.Name, - "lagoon.sh/controller": r.ControllerNamespace, - "lagoon.sh/buildRemoteID": string(lagoonBuild.ObjectMeta.UID), - }, - OwnerReferences: []metav1.OwnerReference{ - { - APIVersion: fmt.Sprintf("%v", lagoonv1alpha1.GroupVersion), - Kind: "LagoonBuild", - Name: lagoonBuild.ObjectMeta.Name, - UID: lagoonBuild.UID, - }, - }, - }, - Spec: corev1.PodSpec{ - RestartPolicy: "Never", - Volumes: []corev1.Volume{ - { - Name: serviceaccountTokenSecret, - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: serviceaccountTokenSecret, - DefaultMode: intPtr(420), - }, - }, - }, - { - Name: "lagoon-sshkey", - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: "lagoon-sshkey", - DefaultMode: intPtr(420), - }, - }, - }, - }, - Tolerations: []corev1.Toleration{ - { - Key: "lagoon/build", - Effect: "NoSchedule", - Operator: "Exists", - }, - { - Key: "lagoon/build", - Effect: "PreferNoSchedule", - Operator: "Exists", - }, - { - Key: "lagoon.sh/build", - Effect: "NoSchedule", - Operator: "Exists", - }, - { - Key: "lagoon.sh/build", - Effect: "PreferNoSchedule", - Operator: "Exists", - }, - }, - Containers: []corev1.Container{ - { - Name: "lagoon-build", - Image: buildImage, - ImagePullPolicy: "Always", - Env: podEnvs, - VolumeMounts: []corev1.VolumeMount{ - { - Name: serviceaccountTokenSecret, - ReadOnly: true, - MountPath: "/var/run/secrets/lagoon/deployer", - }, - { - Name: "lagoon-sshkey", - ReadOnly: true, - MountPath: "/var/run/secrets/lagoon/ssh", - }, - }, - }, - }, - }, - } - - // set the pod security context, if defined to a non-default value - if r.BuildPodRunAsUser != 0 || r.BuildPodRunAsGroup != 0 || - r.BuildPodFSGroup != 0 { - newPod.Spec.SecurityContext = &corev1.PodSecurityContext{ - RunAsUser: &r.BuildPodRunAsUser, - RunAsGroup: &r.BuildPodRunAsGroup, - FSGroup: &r.BuildPodFSGroup, - } - } - - // openshift uses a builder service account to be able to push images to the openshift registry - // load that into the podspec here - if r.IsOpenshift { - newPod.Spec.ServiceAccountName = "builder" - builderToken := corev1.VolumeMount{ - Name: builderServiceaccountTokenSecret, - ReadOnly: true, - MountPath: "/var/run/secrets/kubernetes.io/serviceaccount", - } - builderVolume := corev1.Volume{ - Name: builderServiceaccountTokenSecret, - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: builderServiceaccountTokenSecret, - DefaultMode: intPtr(420), - }, - }, - } - newPod.Spec.Volumes = append(newPod.Spec.Volumes, builderVolume) - newPod.Spec.Containers[0].VolumeMounts = append(newPod.Spec.Containers[0].VolumeMounts, builderToken) - } - opLog.Info(fmt.Sprintf("Checking build pod for: %s", lagoonBuild.ObjectMeta.Name)) - // once the pod spec has been defined, check if it isn't already created - err = r.Get(ctx, types.NamespacedName{ - Namespace: lagoonBuild.ObjectMeta.Namespace, - Name: newPod.ObjectMeta.Name, - }, newPod) - if err != nil { - // if it doesn't exist, then create the build pod - opLog.Info(fmt.Sprintf("Creating build pod for: %s", lagoonBuild.ObjectMeta.Name)) - if err := r.Create(ctx, newPod); err != nil { - opLog.Error(err, fmt.Sprintf("Unable to create build pod")) - // log the error and just exit, don't continue to try and do anything - // @TODO: should update the build to failed - return ctrl.Result{}, nil - } - // then break out of the build - break - } else { - opLog.Info(fmt.Sprintf("Build pod already running for: %s", lagoonBuild.ObjectMeta.Name)) - } - } // end check if running build is current LagoonBuild - } // end loop for running builds - - // if there are no running builds, check if there are any pending builds - if len(runningBuilds.Items) == 0 { - pendingBuilds := &lagoonv1alpha1.LagoonBuildList{} - listOption = (&client.ListOptions{}).ApplyOptions([]client.ListOption{ ->>>>>>> main client.InNamespace(req.Namespace), client.MatchingLabels(map[string]string{ "lagoon.sh/buildStatus": "Running", From 7acc9e8d99280557906d4408364a28a17eb6330a Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 3 Sep 2021 13:37:04 +1000 Subject: [PATCH 11/35] refactor: add bulkid to spec and fix up tests --- .github/workflows/lagoon-kbd.yaml | 6 ++++-- config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/lagoon-kbd.yaml b/.github/workflows/lagoon-kbd.yaml index 70d12961..058a5260 100644 --- a/.github/workflows/lagoon-kbd.yaml +++ b/.github/workflows/lagoon-kbd.yaml @@ -28,8 +28,10 @@ jobs: curl -sLo /tmp/kustomize_v3.5.4_linux_amd64.tar.gz https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv3.5.4/kustomize_v3.5.4_linux_amd64.tar.gz sudo tar -C /usr/local/bin -xzf /tmp/kustomize_v3.5.4_linux_amd64.tar.gz #kubebuilder - curl -sL https://go.kubebuilder.io/dl/2.2.0/linux/amd64 | tar -xz -C /tmp/ - sudo mv /tmp/kubebuilder_2.2.0_linux_amd64 /usr/local/kubebuilder + curl -sL https://github.com/kubernetes-sigs/kubebuilder/releases/download/v2.2.0/kubebuilder_2.2.0_linux_amd64.tar.gz | tar -xz -C /tmp/ + sudo mkdir -p /usr/local/kubebuilder/bin + sudo mv /tmp/kubebuilder_2.2.0_linux_amd64/bin/* /usr/local/kubebuilder/bin + chmod +x /usr/local/kubebuilder/bin/* #helm curl -sL https://get.helm.sh/helm-v3.3.0-rc.1-linux-amd64.tar.gz | tar -xz -C /tmp/ sudo mv /tmp/linux-amd64/helm /usr/local/bin/helm diff --git a/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml b/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml index 3c7e22d0..d5492a74 100644 --- a/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml +++ b/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml @@ -44,6 +44,8 @@ spec: description: Build contains the type of build, and the image to use for the builder. properties: + bulkId: + type: string ci: type: string image: From f657c74c2c7c0f0ff4fc37d96cd15b077a68cfc9 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 3 Sep 2021 19:26:09 +1000 Subject: [PATCH 12/35] fix: lock ingress-nginx version --- controller-test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/controller-test.sh b/controller-test.sh index b5cef773..9ff0e2aa 100755 --- a/controller-test.sh +++ b/controller-test.sh @@ -184,11 +184,11 @@ echo "===> Docker-host is running" echo "===> Install Ingress-Nginx" kubectl create namespace ingress-nginx helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx -helm upgrade --install -n ingress-nginx ingress-nginx ingress-nginx/ingress-nginx -f test-resources/ingress-nginx-values.yaml +helm upgrade --install -n ingress-nginx ingress-nginx ingress-nginx/ingress-nginx -f test-resources/ingress-nginx-values.yaml --version 3.31.0 NUM_PODS=$(kubectl -n ingress-nginx get pods | grep -ow "Running"| wc -l | tr -d " ") if [ $NUM_PODS -ne 1 ]; then echo "Install ingress-nginx" - helm upgrade --install -n ingress-nginx ingress-nginx ingress-nginx/ingress-nginx -f test-resources/ingress-nginx-values.yaml + helm upgrade --install -n ingress-nginx ingress-nginx ingress-nginx/ingress-nginx -f test-resources/ingress-nginx-values.yaml --version 3.31.0 kubectl get pods --all-namespaces echo "Wait for ingress-nginx to become ready" sleep 120 From f6a7f01370c4b6687c6073abb34c220bff9ce4f4 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Mon, 6 Sep 2021 10:19:23 +1000 Subject: [PATCH 13/35] feat: add lagoonbuild cleanup, and minor refactoring --- api/v1alpha1/lagoonbuild_types.go | 22 ++++--- controllers/helpers.go | 4 +- controllers/lagoon_harborintegration.go | 3 +- controllers/lagoonbuild_controller.go | 6 +- controllers/lagoonbuild_deletionhandlers.go | 14 ++--- controllers/lagoonbuild_qoshandler.go | 6 +- controllers/lagoonbuild_standardhandler.go | 2 +- controllers/lagoonmonitor_buildhandlers.go | 24 +++---- controllers/lagoonmonitor_controller.go | 2 +- controllers/lagoonmonitor_taskhandlers.go | 12 ++-- handlers/misctask_handler.go | 2 +- .../{pod_cleanup.go => resource_cleanup.go} | 62 ++++++++++++++++++- main.go | 23 ++++++- 13 files changed, 130 insertions(+), 52 deletions(-) rename handlers/{pod_cleanup.go => resource_cleanup.go} (64%) diff --git a/api/v1alpha1/lagoonbuild_types.go b/api/v1alpha1/lagoonbuild_types.go index 537e1c18..faca0dbd 100644 --- a/api/v1alpha1/lagoonbuild_types.go +++ b/api/v1alpha1/lagoonbuild_types.go @@ -20,17 +20,21 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// JobConditionType const for the status type -type JobConditionType string +// BuildStatusType const for the status type +type BuildStatusType string // These are valid conditions of a job. const ( - // BuildComplete means the build has completed its execution. - JobComplete JobConditionType = "Complete" - // BuildFailed means the job has failed its execution. - JobFailed JobConditionType = "Failed" - // BuildFailed means the job has failed its execution. - JobCancelled JobConditionType = "Cancelled" + // BuildStatusRunning means the build is pending. + BuildStatusPending BuildStatusType = "Pending" + // BuildStatusRunning means the build is running. + BuildStatusRunning BuildStatusType = "Running" + // BuildStatusComplete means the build has completed its execution. + BuildStatusComplete BuildStatusType = "Complete" + // BuildStatusFailed means the job has failed its execution. + BuildStatusFailed BuildStatusType = "Failed" + // BuildStatusCancelled means the job been cancelled. + BuildStatusCancelled BuildStatusType = "Cancelled" ) // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! @@ -65,7 +69,7 @@ type LagoonBuildStatus struct { type LagoonConditions struct { LastTransitionTime string `json:"lastTransitionTime"` Status corev1.ConditionStatus `json:"status"` - Type JobConditionType `json:"type"` + Type BuildStatusType `json:"type"` // Condition string `json:"condition"` } diff --git a/controllers/helpers.go b/controllers/helpers.go index 4195b176..c90fd4e6 100644 --- a/controllers/helpers.go +++ b/controllers/helpers.go @@ -180,7 +180,7 @@ func variableExists(vars *[]LagoonEnvironmentVariable, name, value string) bool func cancelExtraBuilds(ctx context.Context, r client.Client, opLog logr.Logger, pendingBuilds *lagoonv1alpha1.LagoonBuildList, ns string, status string) error { listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ client.InNamespace(ns), - client.MatchingLabels(map[string]string{"lagoon.sh/buildStatus": "Pending"}), + client.MatchingLabels(map[string]string{"lagoon.sh/buildStatus": string(lagoonv1alpha1.BuildStatusPending)}), }) if err := r.List(ctx, pendingBuilds, listOption); err != nil { return fmt.Errorf("Unable to list builds in the namespace, there may be none or something went wrong: %v", err) @@ -198,7 +198,7 @@ func cancelExtraBuilds(ctx context.Context, r client.Client, opLog logr.Logger, pendingBuild.Labels["lagoon.sh/buildStatus"] = status } else { // cancel any other pending builds - pendingBuild.Labels["lagoon.sh/buildStatus"] = "Cancelled" + pendingBuild.Labels["lagoon.sh/buildStatus"] = string(lagoonv1alpha1.BuildStatusCancelled) } if err := r.Update(ctx, pendingBuild); err != nil { return err diff --git a/controllers/lagoon_harborintegration.go b/controllers/lagoon_harborintegration.go index 1cc59823..bb29b7e3 100644 --- a/controllers/lagoon_harborintegration.go +++ b/controllers/lagoon_harborintegration.go @@ -350,7 +350,8 @@ func (h *Harbor) RotateRobotCredentials(ctx context.Context, cl client.Client) { // if there are any builds pending or running, don't try and refresh the credentials as this // could break the build if len(lagoonBuilds.Items) > 0 { - if lagoonBuilds.Items[0].Labels["lagoon.sh/buildStatus"] == "Running" || lagoonBuilds.Items[0].Labels["lagoon.sh/buildStatus"] == "Pending" { + if lagoonBuilds.Items[0].Labels["lagoon.sh/buildStatus"] == string(lagoonv1alpha1.BuildStatusRunning) || + lagoonBuilds.Items[0].Labels["lagoon.sh/buildStatus"] == string(lagoonv1alpha1.BuildStatusPending) { runningBuilds = true } } diff --git a/controllers/lagoonbuild_controller.go b/controllers/lagoonbuild_controller.go index 93d4013d..c8ca819f 100644 --- a/controllers/lagoonbuild_controller.go +++ b/controllers/lagoonbuild_controller.go @@ -99,7 +99,7 @@ func (r *LagoonBuildReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ client.InNamespace(req.Namespace), client.MatchingLabels(map[string]string{ - "lagoon.sh/buildStatus": "Running", + "lagoon.sh/buildStatus": string(lagoonv1alpha1.BuildStatusRunning), "lagoon.sh/controller": r.ControllerNamespace, }), }) @@ -207,7 +207,7 @@ func (r *LagoonBuildReconciler) createNamespaceBuild(ctx context.Context, // the `lagoon.sh/buildStatus = Pending` now // so end this reconcile process pendingBuilds := &lagoonv1alpha1.LagoonBuildList{} - return ctrl.Result{}, cancelExtraBuilds(ctx, r, opLog, pendingBuilds, namespace.ObjectMeta.Name, "Pending") + return ctrl.Result{}, cancelExtraBuilds(ctx, r, opLog, pendingBuilds, namespace.ObjectMeta.Name, string(lagoonv1alpha1.BuildStatusPending)) // return ctrl.Result{}, nil } @@ -219,7 +219,7 @@ func (r *LagoonBuildReconciler) getOrCreateBuildResource(ctx context.Context, bu newBuild.SetResourceVersion("") newBuild.SetLabels( map[string]string{ - "lagoon.sh/buildStatus": "Pending", + "lagoon.sh/buildStatus": string(lagoonv1alpha1.BuildStatusPending), "lagoon.sh/controller": r.ControllerNamespace, }, ) diff --git a/controllers/lagoonbuild_deletionhandlers.go b/controllers/lagoonbuild_deletionhandlers.go index a119ef3e..fb851ad3 100644 --- a/controllers/lagoonbuild_deletionhandlers.go +++ b/controllers/lagoonbuild_deletionhandlers.go @@ -86,7 +86,7 @@ func (r *LagoonBuildReconciler) deleteExternalResources( listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ client.InNamespace(lagoonBuild.ObjectMeta.Namespace), client.MatchingLabels(map[string]string{ - "lagoon.sh/buildStatus": "Running", + "lagoon.sh/buildStatus": string(lagoonv1alpha1.BuildStatusRunning), "lagoon.sh/controller": r.ControllerNamespace, }), }) @@ -110,7 +110,7 @@ func (r *LagoonBuildReconciler) deleteExternalResources( listOption = (&client.ListOptions{}).ApplyOptions([]client.ListOption{ client.InNamespace(lagoonBuild.ObjectMeta.Namespace), client.MatchingLabels(map[string]string{ - "lagoon.sh/buildStatus": "Pending", + "lagoon.sh/buildStatus": string(lagoonv1alpha1.BuildStatusPending), "lagoon.sh/controller": r.ControllerNamespace, }), }) @@ -137,7 +137,7 @@ func (r *LagoonBuildReconciler) deleteExternalResources( mergePatch, _ := json.Marshal(map[string]interface{}{ "metadata": map[string]interface{}{ "labels": map[string]interface{}{ - "lagoon.sh/buildStatus": "Running", + "lagoon.sh/buildStatus": string(lagoonv1alpha1.BuildStatusRunning), }, }, }) @@ -165,8 +165,8 @@ func (r *LagoonBuildReconciler) updateDeploymentWithLogs( // so we don't have to do anything else. if containsString( []string{ - "Pending", - "Running", + string(lagoonv1alpha1.BuildStatusPending), + string(lagoonv1alpha1.BuildStatusRunning), }, lagoonBuild.Labels["lagoon.sh/buildStatus"], ) { @@ -185,8 +185,8 @@ func (r *LagoonBuildReconciler) updateDeploymentWithLogs( ======================================== Build cancelled ========================================`)) - var jobCondition lagoonv1alpha1.JobConditionType - jobCondition = lagoonv1alpha1.JobCancelled + var jobCondition lagoonv1alpha1.BuildStatusType + jobCondition = lagoonv1alpha1.BuildStatusCancelled lagoonBuild.Labels["lagoon.sh/buildStatus"] = string(jobCondition) mergePatch, _ := json.Marshal(map[string]interface{}{ "metadata": map[string]interface{}{ diff --git a/controllers/lagoonbuild_qoshandler.go b/controllers/lagoonbuild_qoshandler.go index 182a399d..0a6f01d2 100644 --- a/controllers/lagoonbuild_qoshandler.go +++ b/controllers/lagoonbuild_qoshandler.go @@ -37,7 +37,7 @@ func (r *LagoonBuildReconciler) qosBuildProcessor(ctx context.Context, func (r *LagoonBuildReconciler) whichBuildNext(ctx context.Context, opLog logr.Logger) error { listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ client.MatchingLabels(map[string]string{ - "lagoon.sh/buildStatus": "Running", + "lagoon.sh/buildStatus": string(lagoonv1alpha1.BuildStatusRunning), "lagoon.sh/controller": r.ControllerNamespace, }), }) @@ -56,7 +56,7 @@ func (r *LagoonBuildReconciler) whichBuildNext(ctx context.Context, opLog logr.L // if there are any free slots to start a build, do that here listOption = (&client.ListOptions{}).ApplyOptions([]client.ListOption{ client.MatchingLabels(map[string]string{ - "lagoon.sh/buildStatus": "Pending", + "lagoon.sh/buildStatus": string(lagoonv1alpha1.BuildStatusPending), "lagoon.sh/controller": r.ControllerNamespace, }), }) @@ -93,7 +93,7 @@ func (r *LagoonBuildReconciler) whichBuildNext(ctx context.Context, opLog logr.L listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ client.InNamespace(pBuild.ObjectMeta.Namespace), client.MatchingLabels(map[string]string{ - "lagoon.sh/buildStatus": "Running", + "lagoon.sh/buildStatus": string(lagoonv1alpha1.BuildStatusRunning), "lagoon.sh/controller": r.ControllerNamespace, }), }) diff --git a/controllers/lagoonbuild_standardhandler.go b/controllers/lagoonbuild_standardhandler.go index ad353110..b51482be 100644 --- a/controllers/lagoonbuild_standardhandler.go +++ b/controllers/lagoonbuild_standardhandler.go @@ -29,7 +29,7 @@ func (r *LagoonBuildReconciler) standardBuildProcessor(ctx context.Context, listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ client.InNamespace(req.Namespace), client.MatchingLabels(map[string]string{ - "lagoon.sh/buildStatus": "Running", + "lagoon.sh/buildStatus": string(lagoonv1alpha1.BuildStatusRunning), "lagoon.sh/controller": r.ControllerNamespace, }), }) diff --git a/controllers/lagoonmonitor_buildhandlers.go b/controllers/lagoonmonitor_buildhandlers.go index 677cf72a..fbd0036d 100644 --- a/controllers/lagoonmonitor_buildhandlers.go +++ b/controllers/lagoonmonitor_buildhandlers.go @@ -56,11 +56,11 @@ func (r *LagoonMonitorReconciler) handleBuildMonitor(ctx context.Context, if container.State.Waiting != nil && containsString(failureStates, container.State.Waiting.Reason) { // if we have a failure state, then fail the build and get the logs from the container opLog.Info(fmt.Sprintf("Build failed, container exit reason was: %v", container.State.Waiting.Reason)) - lagoonBuild.Labels["lagoon.sh/buildStatus"] = string(lagoonv1alpha1.JobFailed) + lagoonBuild.Labels["lagoon.sh/buildStatus"] = string(lagoonv1alpha1.BuildStatusFailed) if err := r.Update(ctx, &lagoonBuild); err != nil { return err } - opLog.Info(fmt.Sprintf("Marked build %s as %s", lagoonBuild.ObjectMeta.Name, string(lagoonv1alpha1.JobFailed))) + opLog.Info(fmt.Sprintf("Marked build %s as %s", lagoonBuild.ObjectMeta.Name, string(lagoonv1alpha1.BuildStatusFailed))) if err := r.Delete(ctx, &jobPod); err != nil { return err } @@ -77,7 +77,7 @@ func (r *LagoonMonitorReconciler) handleBuildMonitor(ctx context.Context, } jobPod.Status.ContainerStatuses[0] = state r.updateBuildStatusCondition(ctx, &lagoonBuild, lagoonv1alpha1.LagoonConditions{ - Type: lagoonv1alpha1.JobFailed, + Type: lagoonv1alpha1.BuildStatusFailed, Status: corev1.ConditionTrue, }, []byte(container.State.Waiting.Message)) @@ -142,7 +142,7 @@ func (r *LagoonMonitorReconciler) buildLogsToLagoonLogs(ctx context.Context, condition = "complete" } if bStatus, ok := lagoonBuild.Labels["lagoon.sh/buildStatus"]; ok { - if bStatus == "Cancelled" { + if bStatus == string(lagoonv1alpha1.BuildStatusCancelled) { condition = "cancelled" } } @@ -201,7 +201,7 @@ func (r *LagoonMonitorReconciler) updateDeploymentAndEnvironmentTask(ctx context condition = "complete" } if bStatus, ok := lagoonBuild.Labels["lagoon.sh/buildStatus"]; ok { - if bStatus == "Cancelled" { + if bStatus == string(lagoonv1alpha1.BuildStatusCancelled) { condition = "cancelled" } } @@ -308,7 +308,7 @@ func (r *LagoonMonitorReconciler) buildStatusLogsToLagoonLogs(ctx context.Contex condition = "complete" } if bStatus, ok := lagoonBuild.Labels["lagoon.sh/buildStatus"]; ok { - if bStatus == "Cancelled" { + if bStatus == string(lagoonv1alpha1.BuildStatusCancelled) { condition = "cancelled" } } @@ -491,15 +491,15 @@ func (r *LagoonMonitorReconciler) updateDeploymentWithLogs( cancel bool, ) error { opLog := r.Log.WithValues("lagoonmonitor", req.NamespacedName) - var jobCondition lagoonv1alpha1.JobConditionType + var jobCondition lagoonv1alpha1.BuildStatusType switch jobPod.Status.Phase { case corev1.PodFailed: - jobCondition = lagoonv1alpha1.JobFailed + jobCondition = lagoonv1alpha1.BuildStatusFailed case corev1.PodSucceeded: - jobCondition = lagoonv1alpha1.JobComplete + jobCondition = lagoonv1alpha1.BuildStatusComplete } if cancel { - jobCondition = lagoonv1alpha1.JobCancelled + jobCondition = lagoonv1alpha1.BuildStatusCancelled } // if the build status is Pending or Running // then the jobCondition is Failed, Complete, or Cancelled @@ -507,8 +507,8 @@ func (r *LagoonMonitorReconciler) updateDeploymentWithLogs( // we do this so we don't update the status of the build again if containsString( []string{ - "Pending", - "Running", + string(lagoonv1alpha1.BuildStatusPending), + string(lagoonv1alpha1.BuildStatusRunning), }, lagoonBuild.Labels["lagoon.sh/buildStatus"], ) { diff --git a/controllers/lagoonmonitor_controller.go b/controllers/lagoonmonitor_controller.go index 7dafec30..76a8885f 100644 --- a/controllers/lagoonmonitor_controller.go +++ b/controllers/lagoonmonitor_controller.go @@ -117,7 +117,7 @@ func (r *LagoonMonitorReconciler) Reconcile(req ctrl.Request) (ctrl.Result, erro runningBuilds := &lagoonv1alpha1.LagoonBuildList{} listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ client.InNamespace(req.Namespace), - client.MatchingLabels(map[string]string{"lagoon.sh/buildStatus": "Running"}), + client.MatchingLabels(map[string]string{"lagoon.sh/buildStatus": string(lagoonv1alpha1.BuildStatusRunning)}), }) // list all builds in the namespace that have the running buildstatus if err := r.List(ctx, runningBuilds, listOption); err != nil { diff --git a/controllers/lagoonmonitor_taskhandlers.go b/controllers/lagoonmonitor_taskhandlers.go index d718dcd0..41271b7d 100644 --- a/controllers/lagoonmonitor_taskhandlers.go +++ b/controllers/lagoonmonitor_taskhandlers.go @@ -33,11 +33,11 @@ func (r *LagoonMonitorReconciler) handleTaskMonitor(ctx context.Context, opLog l if container.State.Waiting != nil && containsString(failureStates, container.State.Waiting.Reason) { // if we have a failure state, then fail the build and get the logs from the container opLog.Info(fmt.Sprintf("Task failed, container exit reason was: %v", container.State.Waiting.Reason)) - lagoonTask.Labels["lagoon.sh/taskStatus"] = string(lagoonv1alpha1.JobFailed) + lagoonTask.Labels["lagoon.sh/taskStatus"] = string(lagoonv1alpha1.BuildStatusFailed) if err := r.Update(ctx, &lagoonTask); err != nil { return err } - opLog.Info(fmt.Sprintf("Marked task %s as %s", lagoonTask.ObjectMeta.Name, string(lagoonv1alpha1.JobFailed))) + opLog.Info(fmt.Sprintf("Marked task %s as %s", lagoonTask.ObjectMeta.Name, string(lagoonv1alpha1.BuildStatusFailed))) if err := r.Delete(ctx, &jobPod); err != nil { return err } @@ -54,7 +54,7 @@ func (r *LagoonMonitorReconciler) handleTaskMonitor(ctx context.Context, opLog l } jobPod.Status.ContainerStatuses[0] = state r.updateTaskStatusCondition(ctx, &lagoonTask, lagoonv1alpha1.LagoonConditions{ - Type: lagoonv1alpha1.JobFailed, + Type: lagoonv1alpha1.BuildStatusFailed, Status: corev1.ConditionTrue, }, []byte(container.State.Waiting.Message)) // send any messages to lagoon message queues @@ -76,12 +76,12 @@ func (r *LagoonMonitorReconciler) handleTaskMonitor(ctx context.Context, opLog l if err != nil { return err } - var jobCondition lagoonv1alpha1.JobConditionType + var jobCondition lagoonv1alpha1.BuildStatusType switch jobPod.Status.Phase { case corev1.PodFailed: - jobCondition = lagoonv1alpha1.JobFailed + jobCondition = lagoonv1alpha1.BuildStatusFailed case corev1.PodSucceeded: - jobCondition = lagoonv1alpha1.JobComplete + jobCondition = lagoonv1alpha1.BuildStatusComplete } // if the build status doesn't equal the status of the pod // then update the build to reflect the current pod status diff --git a/handlers/misctask_handler.go b/handlers/misctask_handler.go index 58148610..84c4085b 100644 --- a/handlers/misctask_handler.go +++ b/handlers/misctask_handler.go @@ -39,7 +39,7 @@ func (h *Messaging) CancelDeployment(jobSpec *lagoonv1alpha1.LagoonTaskSpec) err } // as there is no build pod, but there is a lagoon build resource // update it to cancelled so that the controller doesn't try to run it - lagoonBuild.ObjectMeta.Labels["lagoon.sh/buildStatus"] = "Cancelled" + lagoonBuild.ObjectMeta.Labels["lagoon.sh/buildStatus"] = string(lagoonv1alpha1.BuildStatusCancelled) if err := h.Client.Update(context.Background(), &lagoonBuild); err != nil { opLog.Error(err, fmt.Sprintf( diff --git a/handlers/pod_cleanup.go b/handlers/resource_cleanup.go similarity index 64% rename from handlers/pod_cleanup.go rename to handlers/resource_cleanup.go index 3dff0b44..673655a2 100644 --- a/handlers/pod_cleanup.go +++ b/handlers/resource_cleanup.go @@ -10,9 +10,12 @@ import ( "k8s.io/apimachinery/pkg/selection" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" + + lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" ) type cleanup interface { + LagoonBuildCleanup() BuildPodCleanup() TaskPodCleanup() } @@ -20,23 +23,76 @@ type cleanup interface { // Cleanup is used for cleaning up old pods or resources. type Cleanup struct { Client client.Client - TaskPodsToKeep int + BuildsToKeep int BuildPodsToKeep int + TaskPodsToKeep int ControllerNamespace string EnableDebug bool } // NewCleanup returns a cleanup with controller-runtime client. -func NewCleanup(client client.Client, taskPodsToKeep int, buildPodsToKeep int, controllerNamespace string, enableDebug bool) *Cleanup { +func NewCleanup(client client.Client, buildsToKeep int, buildPodsToKeep int, taskPodsToKeep int, controllerNamespace string, enableDebug bool) *Cleanup { return &Cleanup{ Client: client, - TaskPodsToKeep: taskPodsToKeep, + BuildsToKeep: buildsToKeep, BuildPodsToKeep: buildPodsToKeep, + TaskPodsToKeep: taskPodsToKeep, ControllerNamespace: controllerNamespace, EnableDebug: enableDebug, } } +// LagoonBuildCleanup will clean up any build crds that are hanging around. +func (h *Cleanup) LagoonBuildCleanup() { + opLog := ctrl.Log.WithName("handlers").WithName("LagoonBuildCleanup") + namespaces := &corev1.NamespaceList{} + labelRequirements, _ := labels.NewRequirement("lagoon.sh/environmentType", selection.Exists, nil) + listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ + client.MatchingLabelsSelector{ + Selector: labels.NewSelector().Add(*labelRequirements), + }, + }) + if err := h.Client.List(context.Background(), namespaces, listOption); err != nil { + opLog.Error(err, fmt.Sprintf("Unable to list namespaces created by Lagoon, there may be none or something went wrong")) + return + } + for _, ns := range namespaces.Items { + opLog.Info(fmt.Sprintf("Checking LagoonBuilds in namespace %s", ns.ObjectMeta.Name)) + lagoonBuilds := &lagoonv1alpha1.LagoonBuildList{} + listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ + client.InNamespace(ns.ObjectMeta.Name), + client.MatchingLabels(map[string]string{ + "lagoon.sh/jobType": "build", + "lagoon.sh/controller": h.ControllerNamespace, // created by this controller + }), + }) + if err := h.Client.List(context.Background(), lagoonBuilds, listOption); err != nil { + opLog.Error(err, fmt.Sprintf("Unable to list LagoonBuild resources, there may be none or something went wrong")) + return + } + // sort the build pods by creation timestamp + sort.Slice(lagoonBuilds.Items, func(i, j int) bool { + return lagoonBuilds.Items[i].ObjectMeta.CreationTimestamp.After(lagoonBuilds.Items[j].ObjectMeta.CreationTimestamp.Time) + }) + if len(lagoonBuilds.Items) > h.BuildsToKeep { + for idx, lagoonBuild := range lagoonBuilds.Items { + if idx >= h.BuildsToKeep { + if lagoonBuild.ObjectMeta.Annotations["lagoon.sh/buildStatus"] == string(lagoonv1alpha1.BuildStatusFailed) || + lagoonBuild.ObjectMeta.Annotations["lagoon.sh/buildStatus"] == string(lagoonv1alpha1.BuildStatusComplete) || + lagoonBuild.ObjectMeta.Annotations["lagoon.sh/buildStatus"] == string(lagoonv1alpha1.BuildStatusCancelled) { + opLog.Info(fmt.Sprintf("Cleaning up LagoonBuild %s", lagoonBuild.ObjectMeta.Name)) + if err := h.Client.Delete(context.Background(), &lagoonBuild); err != nil { + opLog.Error(err, fmt.Sprintf("Unable to update status condition")) + break + } + } + } + } + } + } + return +} + // BuildPodCleanup will clean up any build pods that are hanging around. func (h *Cleanup) BuildPodCleanup() { opLog := ctrl.Log.WithName("handlers").WithName("BuildPodCleanup") diff --git a/main.go b/main.go index 5837126a..d1f8fecf 100644 --- a/main.go +++ b/main.go @@ -101,8 +101,11 @@ func main() { var lffDefaultIsolationNetworkPolicy string var buildPodCleanUpEnable bool var taskPodCleanUpEnable bool + var buildsCleanUpEnable bool var buildPodCleanUpCron string var taskPodCleanUpCron string + var buildsCleanUpCron string + var buildsToKeep int var buildPodsToKeep int var taskPodsToKeep int var lffBackupWeeklyRandom bool @@ -201,6 +204,10 @@ func main() { flag.BoolVar(&buildPodCleanUpEnable, "enable-build-pod-cleanup", true, "Flag to enable build pod cleanup.") flag.StringVar(&buildPodCleanUpCron, "build-pod-cleanup-cron", "0 * * * *", "The cron definition for how often to run the build pod cleanup.") + flag.BoolVar(&buildsCleanUpEnable, "enable-lagoonbuilds-cleanup", true, "Flag to enable lagoonbuild resources cleanup.") + flag.StringVar(&buildsCleanUpCron, "lagoonbuilds-cleanup-cron", "0 * * * *", + "The cron definition for how often to run the lagoonbuild resources cleanup.") + flag.IntVar(&buildsToKeep, "num-builds-to-keep", 5, "The number of lagoonbuild resources to keep per namespace.") flag.IntVar(&buildPodsToKeep, "num-build-pods-to-keep", 1, "The number of build pods to keep per namespace.") flag.BoolVar(&taskPodCleanUpEnable, "enable-task-pod-cleanup", true, "Flag to enable build pod cleanup.") flag.StringVar(&taskPodCleanUpCron, "task-pod-cleanup-cron", "30 * * * *", @@ -503,19 +510,29 @@ func main() { DefaultValue: qosDefaultValue, } - podCleanup := handlers.NewCleanup(mgr.GetClient(), + resourceCleanup := handlers.NewCleanup(mgr.GetClient(), + buildsToKeep, buildPodsToKeep, taskPodsToKeep, controllerNamespace, enableDebug, ) + // if the lagoonbuild cleanup is enabled, add the cronjob for it + if buildsCleanUpEnable { + setupLog.Info("starting LagoonBuild CRD cleanup handler") + // use cron to run a lagoonbuild cleanup task + // this will check any Lagoon builds and attempt to delete them + c.AddFunc(buildsCleanUpCron, func() { + resourceCleanup.LagoonBuildCleanup() + }) + } // if the build pod cleanup is enabled, add the cronjob for it if buildPodCleanUpEnable { setupLog.Info("starting build pod cleanup handler") // use cron to run a build pod cleanup task // this will check any Lagoon build pods and attempt to delete them c.AddFunc(buildPodCleanUpCron, func() { - podCleanup.BuildPodCleanup() + resourceCleanup.BuildPodCleanup() }) } // if the task pod cleanup is enabled, add the cronjob for it @@ -524,7 +541,7 @@ func main() { // use cron to run a task pod cleanup task // this will check any Lagoon task pods and attempt to delete them c.AddFunc(taskPodCleanUpCron, func() { - podCleanup.TaskPodCleanup() + resourceCleanup.TaskPodCleanup() }) } // if harbor is enabled, add the cronjob for credential rotation From 258870545b51e92972510c452f392a90038def85 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Mon, 6 Sep 2021 11:01:38 +1000 Subject: [PATCH 14/35] chore: fix kustomize templates --- config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml | 2 +- config/crd/bases/lagoon.amazee.io_lagoontasks.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml b/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml index d5492a74..d2f587ff 100644 --- a/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml +++ b/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml @@ -174,7 +174,7 @@ spec: status: type: string type: - description: JobConditionType const for the status type + description: BuildStatusType const for the status type type: string required: - lastTransitionTime diff --git a/config/crd/bases/lagoon.amazee.io_lagoontasks.yaml b/config/crd/bases/lagoon.amazee.io_lagoontasks.yaml index 2354ae86..6a9f604f 100644 --- a/config/crd/bases/lagoon.amazee.io_lagoontasks.yaml +++ b/config/crd/bases/lagoon.amazee.io_lagoontasks.yaml @@ -145,7 +145,7 @@ spec: status: type: string type: - description: JobConditionType const for the status type + description: BuildStatusType const for the status type type: string required: - lastTransitionTime From 77c27b21f1d11cbd9eff20b524a895ea84a894db Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Mon, 6 Sep 2021 11:17:30 +1000 Subject: [PATCH 15/35] test: add ingress output to test --- controller-test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/controller-test.sh b/controller-test.sh index 9ff0e2aa..7c67a631 100755 --- a/controller-test.sh +++ b/controller-test.sh @@ -43,8 +43,8 @@ check_controller_log_build () { tear_down () { echo "============= TEAR DOWN =============" - # echo "==> Get pvc" - # kubectl get pvc --all-namespaces + echo "==> Get ingress" + kubectl get ingress --all-namespaces echo "==> Get pods" kubectl get pods --all-namespaces echo "==> Remove cluster" From e7e8f5350c4b83d77faee8ca96bdc30cb7f253f1 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Mon, 6 Sep 2021 15:07:32 +1000 Subject: [PATCH 16/35] refactor: fix up some checks --- controllers/helpers.go | 14 ++ controllers/lagoon_harborintegration.go | 6 +- controllers/lagoonmonitor_buildhandlers.go | 5 +- handlers/helpers.go | 157 +++++++++++++++++++++ handlers/message_queue.go | 13 -- handlers/resource_cleanup.go | 7 +- 6 files changed, 180 insertions(+), 22 deletions(-) create mode 100644 handlers/helpers.go diff --git a/controllers/helpers.go b/controllers/helpers.go index c90fd4e6..dbdd1040 100644 --- a/controllers/helpers.go +++ b/controllers/helpers.go @@ -26,6 +26,20 @@ const ( DefaultNamespacePattern = "${project}-${environment}" ) +var ( + // RunningPendingStatus . + RunningPendingStatus = []string{ + string(lagoonv1alpha1.BuildStatusPending), + string(lagoonv1alpha1.BuildStatusRunning), + } + // CompletedCancelledFailedStatus . + CompletedCancelledFailedStatus = []string{ + string(lagoonv1alpha1.BuildStatusFailed), + string(lagoonv1alpha1.BuildStatusComplete), + string(lagoonv1alpha1.BuildStatusCancelled), + } +) + // ignoreNotFound will ignore not found errors func ignoreNotFound(err error) error { if apierrors.IsNotFound(err) { diff --git a/controllers/lagoon_harborintegration.go b/controllers/lagoon_harborintegration.go index bb29b7e3..78012ae5 100644 --- a/controllers/lagoon_harborintegration.go +++ b/controllers/lagoon_harborintegration.go @@ -350,8 +350,10 @@ func (h *Harbor) RotateRobotCredentials(ctx context.Context, cl client.Client) { // if there are any builds pending or running, don't try and refresh the credentials as this // could break the build if len(lagoonBuilds.Items) > 0 { - if lagoonBuilds.Items[0].Labels["lagoon.sh/buildStatus"] == string(lagoonv1alpha1.BuildStatusRunning) || - lagoonBuilds.Items[0].Labels["lagoon.sh/buildStatus"] == string(lagoonv1alpha1.BuildStatusPending) { + if containsString( + RunningPendingStatus, + lagoonBuilds.Items[0].Labels["lagoon.sh/buildStatus"], + ) { runningBuilds = true } } diff --git a/controllers/lagoonmonitor_buildhandlers.go b/controllers/lagoonmonitor_buildhandlers.go index fbd0036d..481f5dca 100644 --- a/controllers/lagoonmonitor_buildhandlers.go +++ b/controllers/lagoonmonitor_buildhandlers.go @@ -506,10 +506,7 @@ func (r *LagoonMonitorReconciler) updateDeploymentWithLogs( // then update the build to reflect the current pod status // we do this so we don't update the status of the build again if containsString( - []string{ - string(lagoonv1alpha1.BuildStatusPending), - string(lagoonv1alpha1.BuildStatusRunning), - }, + RunningPendingStatus, lagoonBuild.Labels["lagoon.sh/buildStatus"], ) { opLog.Info( diff --git a/handlers/helpers.go b/handlers/helpers.go new file mode 100644 index 00000000..8676450d --- /dev/null +++ b/handlers/helpers.go @@ -0,0 +1,157 @@ +package handlers + +import ( + "crypto/sha1" + "crypto/sha256" + "encoding/base32" + "fmt" + "math/rand" + "regexp" + "strconv" + "strings" + "time" + + lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" + apierrors "k8s.io/apimachinery/pkg/api/errors" +) + +const ( + // LabelAppManaged for discovery. + LabelAppManaged = "lagoon.amazee.io/managed-by" + // DefaultNamespacePattern is what is used when one is not provided. + DefaultNamespacePattern = "${project}-${environment}" +) + +var ( + // RunningPendingStatus . + RunningPendingStatus = []string{ + string(lagoonv1alpha1.BuildStatusPending), + string(lagoonv1alpha1.BuildStatusRunning), + } + // CompletedCancelledFailedStatus . + CompletedCancelledFailedStatus = []string{ + string(lagoonv1alpha1.BuildStatusFailed), + string(lagoonv1alpha1.BuildStatusComplete), + string(lagoonv1alpha1.BuildStatusCancelled), + } +) + +// ignoreNotFound will ignore not found errors +func ignoreNotFound(err error) error { + if apierrors.IsNotFound(err) { + return nil + } + return err +} + +// containsString check if a slice contains a string +func containsString(slice []string, s string) bool { + for _, item := range slice { + if item == s { + return true + } + } + return false +} + +// removeString remove string from a sliced +func removeString(slice []string, s string) (result []string) { + for _, item := range slice { + if item == s { + continue + } + result = append(result, item) + } + return +} + +func jobContainsStatus(slice []lagoonv1alpha1.LagoonConditions, s lagoonv1alpha1.LagoonConditions) bool { + for _, item := range slice { + if item == s { + return true + } + } + return false +} + +func intPtr(i int32) *int32 { + var iPtr *int32 + iPtr = new(int32) + *iPtr = i + return iPtr +} + +func int64Ptr(i int64) *int64 { + var iPtr *int64 + iPtr = new(int64) + *iPtr = i + return iPtr +} + +func uintPtr(i uint) *uint { + var iPtr *uint + iPtr = new(uint) + *iPtr = i + return iPtr +} + +// make safe ensures that any string is dns safe +func makeSafe(in string) string { + out := regexp.MustCompile(`[^0-9a-z-]`).ReplaceAllString( + strings.ToLower(in), + "$1-$2", + ) + return out +} + +const charset = "abcdefghijklmnopqrstuvwxyz0123456789" + +var seededRand *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano())) + +func randString(length int) string { + b := make([]byte, length) + for i := range b { + b[i] = charset[seededRand.Intn(len(charset))] + } + return string(b) +} + +// get the hash of a given string. +func hashString(s string) string { + h := sha1.New() + h.Write([]byte(s)) + bs := h.Sum(nil) + return fmt.Sprintf("%x", bs) +} + +// removeBuild remove a LagoonBuild from a slice of LagoonBuilds +func removeBuild(slice []lagoonv1alpha1.LagoonBuild, s lagoonv1alpha1.LagoonBuild) []lagoonv1alpha1.LagoonBuild { + result := []lagoonv1alpha1.LagoonBuild{} + for _, item := range slice { + if item.ObjectMeta.Name == s.ObjectMeta.Name { + continue + } + result = append(result, item) + } + return result +} + +var lowerAlNum = regexp.MustCompile("[^a-z0-9]+") + +// shortName returns a deterministic random short name of 8 lowercase +// alphabetic and numeric characters. The short name is based +// on hashing and encoding the given name. +func shortName(name string) string { + hash := sha256.Sum256([]byte(name)) + return lowerAlNum.ReplaceAllString(strings.ToLower(base32.StdEncoding.EncodeToString(hash[:])), "")[:8] +} + +func stringToUintPtr(s string) *uint { + // get the environment id and turn it into a *uint to send back to lagoon for logging + // lagoon sends this as a string :( + u64, err := strconv.ParseUint(s, 10, 32) + if err != nil { + return nil + } + return uintPtr(uint(u64)) +} diff --git a/handlers/message_queue.go b/handlers/message_queue.go index e485fea0..e83e6e57 100644 --- a/handlers/message_queue.go +++ b/handlers/message_queue.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" "log" - "math/rand" "strings" "time" @@ -482,15 +481,3 @@ func (h *Messaging) GetPendingMessages() { } return } - -const charset = "abcdefghijklmnopqrstuvwxyz0123456789" - -var seededRand *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano())) - -func randString(length int) string { - b := make([]byte, length) - for i := range b { - b[i] = charset[seededRand.Intn(len(charset))] - } - return string(b) -} diff --git a/handlers/resource_cleanup.go b/handlers/resource_cleanup.go index 673655a2..9198c55a 100644 --- a/handlers/resource_cleanup.go +++ b/handlers/resource_cleanup.go @@ -77,9 +77,10 @@ func (h *Cleanup) LagoonBuildCleanup() { if len(lagoonBuilds.Items) > h.BuildsToKeep { for idx, lagoonBuild := range lagoonBuilds.Items { if idx >= h.BuildsToKeep { - if lagoonBuild.ObjectMeta.Annotations["lagoon.sh/buildStatus"] == string(lagoonv1alpha1.BuildStatusFailed) || - lagoonBuild.ObjectMeta.Annotations["lagoon.sh/buildStatus"] == string(lagoonv1alpha1.BuildStatusComplete) || - lagoonBuild.ObjectMeta.Annotations["lagoon.sh/buildStatus"] == string(lagoonv1alpha1.BuildStatusCancelled) { + if containsString( + CompletedCancelledFailedStatus, + lagoonBuild.ObjectMeta.Annotations["lagoon.sh/buildStatus"], + ) { opLog.Info(fmt.Sprintf("Cleaning up LagoonBuild %s", lagoonBuild.ObjectMeta.Name)) if err := h.Client.Delete(context.Background(), &lagoonBuild); err != nil { opLog.Error(err, fmt.Sprintf("Unable to update status condition")) From d44ea43246b17bd0c00368c26fc186cf2e4f6dc4 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Tue, 7 Sep 2021 10:14:18 +1000 Subject: [PATCH 17/35] refactor: use kebab-case for flags --- main.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/main.go b/main.go index 8fa8dc0a..f9a19ed2 100644 --- a/main.go +++ b/main.go @@ -175,15 +175,15 @@ func main() { flag.UintVar(&buildPodRunAsUser, "build-pod-run-as-user", 0, "The build pod security context runAsUser.") flag.UintVar(&buildPodRunAsGroup, "build-pod-run-as-group", 0, "The build pod security context runAsGroup.") flag.UintVar(&buildPodFSGroup, "build-pod-fs-group", 0, "The build pod security context fsGroup.") - flag.StringVar(&backupDefaultSchedule, "backupDefaultSchedule", "M H(22-2) * * *", + flag.StringVar(&backupDefaultSchedule, "backup-default-schedule", "M H(22-2) * * *", "The default backup schedule for all projects on this cluster.") - flag.IntVar(&backupDefaultMonthlyRetention, "backupDefaultMonthlyRetention", 1, + flag.IntVar(&backupDefaultMonthlyRetention, "backup-default-monthly-retention", 1, "The number of monthly backups k8up should retain after a prune operation.") - flag.IntVar(&backupDefaultWeeklyRetention, "backupDefaultWeeklyRetention", 6, + flag.IntVar(&backupDefaultWeeklyRetention, "backup-default-weekly-retention", 6, "The number of weekly backups k8up should retain after a prune operation.") - flag.IntVar(&backupDefaultDailyRetention, "backupDefaultDailyRetention", 7, + flag.IntVar(&backupDefaultDailyRetention, "backup-default-daily-retention", 7, "The number of daily backups k8up should retain after a prune operation.") - flag.IntVar(&backupDefaultHourlyRetention, "backupDefaultHourlyRetention", 0, + flag.IntVar(&backupDefaultHourlyRetention, "backup-default-hourly-retention", 0, "The number of hourly backups k8up should retain after a prune operation.") // Lagoon feature flags flag.StringVar(&lffForceRootlessWorkload, "lagoon-feature-flag-force-rootless-workload", "", From d8091360d96bcb1022e10e2e263576b684071861 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 1 Oct 2021 10:00:15 +1000 Subject: [PATCH 18/35] refactor: changes to api for tasks and builds to use defined status values now, add task resource cleanup cronjob --- api/v1alpha1/lagoonbuild_types.go | 8 +-- api/v1alpha1/lagoontask_types.go | 41 ++++++++++++- api/v1alpha1/zz_generated.deepcopy.go | 49 ++++++++++------ .../bases/lagoon.amazee.io_lagoonbuilds.yaml | 4 +- .../bases/lagoon.amazee.io_lagoontasks.yaml | 6 +- controllers/helpers.go | 11 +++- controllers/lagoonbuild_helpers.go | 4 +- controllers/lagoonmonitor_buildhandlers.go | 8 +-- controllers/lagoonmonitor_taskhandlers.go | 20 +++---- controllers/lagoontask_controller.go | 6 +- handlers/helpers.go | 30 ++++++++-- handlers/message_queue.go | 4 +- handlers/misctask_handler.go | 4 +- handlers/resource_cleanup.go | 58 ++++++++++++++++++- main.go | 17 ++++++ 15 files changed, 212 insertions(+), 58 deletions(-) diff --git a/api/v1alpha1/lagoonbuild_types.go b/api/v1alpha1/lagoonbuild_types.go index faca0dbd..5aa1ec1e 100644 --- a/api/v1alpha1/lagoonbuild_types.go +++ b/api/v1alpha1/lagoonbuild_types.go @@ -61,12 +61,12 @@ type LagoonBuildSpec struct { type LagoonBuildStatus struct { // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster // Important: Run "make" to regenerate code after modifying this file - Conditions []LagoonConditions `json:"conditions,omitempty"` - Log []byte `json:"log,omitempty"` + Conditions []LagoonBuildConditions `json:"conditions,omitempty"` + Log []byte `json:"log,omitempty"` } -// LagoonConditions defines the observed conditions of the pods. -type LagoonConditions struct { +// LagoonBuildConditions defines the observed conditions of build pods. +type LagoonBuildConditions struct { LastTransitionTime string `json:"lastTransitionTime"` Status corev1.ConditionStatus `json:"status"` Type BuildStatusType `json:"type"` diff --git a/api/v1alpha1/lagoontask_types.go b/api/v1alpha1/lagoontask_types.go index 24cbb705..3b7eda10 100644 --- a/api/v1alpha1/lagoontask_types.go +++ b/api/v1alpha1/lagoontask_types.go @@ -16,12 +16,41 @@ limitations under the License. package v1alpha1 import ( + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! // NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. +// TaskStatusType const for the status type +type TaskStatusType string + +// These are valid conditions of a job. +const ( + // TaskStatusRunning means the build is pending. + TaskStatusPending TaskStatusType = "Pending" + // TaskStatusRunning means the build is running. + TaskStatusRunning TaskStatusType = "Running" + // TaskStatusComplete means the build has completed its execution. + TaskStatusComplete TaskStatusType = "Complete" + // TaskStatusFailed means the job has failed its execution. + TaskStatusFailed TaskStatusType = "Failed" + // TaskStatusCancelled means the job been cancelled. + TaskStatusCancelled TaskStatusType = "Cancelled" +) + +// TaskType const for the status type +type TaskType string + +// These are valid conditions of a job. +const ( + // TaskStatusRunning means the build is pending. + TaskTypeStandard TaskType = "standard" + // TaskStatusRunning means the build is running. + TaskTypeAdvanced TaskType = "advanced" +) + // LagoonTaskSpec defines the desired state of LagoonTask type LagoonTaskSpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster @@ -85,8 +114,16 @@ type LagoonTaskEnvironment struct { type LagoonTaskStatus struct { // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster // Important: Run "make" to regenerate code after modifying this file - Conditions []LagoonConditions `json:"conditions,omitempty"` - Log []byte `json:"log,omitempty"` + Conditions []LagoonTaskConditions `json:"conditions,omitempty"` + Log []byte `json:"log,omitempty"` +} + +// LagoonTaskConditions defines the observed conditions of task pods. +type LagoonTaskConditions struct { + LastTransitionTime string `json:"lastTransitionTime"` + Status corev1.ConditionStatus `json:"status"` + Type TaskStatusType `json:"type"` + // Condition string `json:"condition"` } // +kubebuilder:object:root=true diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index f55cb0fd..b554f721 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -105,6 +105,21 @@ func (in *LagoonBuild) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LagoonBuildConditions) DeepCopyInto(out *LagoonBuildConditions) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LagoonBuildConditions. +func (in *LagoonBuildConditions) DeepCopy() *LagoonBuildConditions { + if in == nil { + return nil + } + out := new(LagoonBuildConditions) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LagoonBuildList) DeepCopyInto(out *LagoonBuildList) { *out = *in @@ -162,7 +177,7 @@ func (in *LagoonBuildStatus) DeepCopyInto(out *LagoonBuildStatus) { *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions - *out = make([]LagoonConditions, len(*in)) + *out = make([]LagoonBuildConditions, len(*in)) copy(*out, *in) } if in.Log != nil { @@ -182,21 +197,6 @@ func (in *LagoonBuildStatus) DeepCopy() *LagoonBuildStatus { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *LagoonConditions) DeepCopyInto(out *LagoonConditions) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LagoonConditions. -func (in *LagoonConditions) DeepCopy() *LagoonConditions { - if in == nil { - return nil - } - out := new(LagoonConditions) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LagoonLog) DeepCopyInto(out *LagoonLog) { *out = *in @@ -384,6 +384,21 @@ func (in *LagoonTask) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LagoonTaskConditions) DeepCopyInto(out *LagoonTaskConditions) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LagoonTaskConditions. +func (in *LagoonTaskConditions) DeepCopy() *LagoonTaskConditions { + if in == nil { + return nil + } + out := new(LagoonTaskConditions) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LagoonTaskEnvironment) DeepCopyInto(out *LagoonTaskEnvironment) { *out = *in @@ -494,7 +509,7 @@ func (in *LagoonTaskStatus) DeepCopyInto(out *LagoonTaskStatus) { *out = *in if in.Conditions != nil { in, out := &in.Conditions, &out.Conditions - *out = make([]LagoonConditions, len(*in)) + *out = make([]LagoonTaskConditions, len(*in)) copy(*out, *in) } if in.Log != nil { diff --git a/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml b/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml index d2f587ff..141985bd 100644 --- a/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml +++ b/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml @@ -166,8 +166,8 @@ spec: of cluster Important: Run "make" to regenerate code after modifying this file' items: - description: LagoonConditions defines the observed conditions of the - pods. + description: LagoonBuildConditions defines the observed conditions + of build pods. properties: lastTransitionTime: type: string diff --git a/config/crd/bases/lagoon.amazee.io_lagoontasks.yaml b/config/crd/bases/lagoon.amazee.io_lagoontasks.yaml index 6a9f604f..0ce34a89 100644 --- a/config/crd/bases/lagoon.amazee.io_lagoontasks.yaml +++ b/config/crd/bases/lagoon.amazee.io_lagoontasks.yaml @@ -137,15 +137,15 @@ spec: of cluster Important: Run "make" to regenerate code after modifying this file' items: - description: LagoonConditions defines the observed conditions of the - pods. + description: LagoonTaskConditions defines the observed conditions + of task pods. properties: lastTransitionTime: type: string status: type: string type: - description: BuildStatusType const for the status type + description: TaskStatusType const for the status type type: string required: - lastTransitionTime diff --git a/controllers/helpers.go b/controllers/helpers.go index dbdd1040..fb5bfdb1 100644 --- a/controllers/helpers.go +++ b/controllers/helpers.go @@ -69,7 +69,16 @@ func removeString(slice []string, s string) (result []string) { return } -func jobContainsStatus(slice []lagoonv1alpha1.LagoonConditions, s lagoonv1alpha1.LagoonConditions) bool { +func buildContainsStatus(slice []lagoonv1alpha1.LagoonBuildConditions, s lagoonv1alpha1.LagoonBuildConditions) bool { + for _, item := range slice { + if item == s { + return true + } + } + return false +} + +func taskContainsStatus(slice []lagoonv1alpha1.LagoonTaskConditions, s lagoonv1alpha1.LagoonTaskConditions) bool { for _, item := range slice { if item == s { return true diff --git a/controllers/lagoonbuild_helpers.go b/controllers/lagoonbuild_helpers.go index 2023e8e6..4c818dd9 100644 --- a/controllers/lagoonbuild_helpers.go +++ b/controllers/lagoonbuild_helpers.go @@ -27,12 +27,12 @@ import ( // updateBuildStatusCondition is used to patch the lagoon build with the status conditions for the build, plus any logs func (r *LagoonBuildReconciler) updateBuildStatusCondition(ctx context.Context, lagoonBuild *lagoonv1alpha1.LagoonBuild, - condition lagoonv1alpha1.LagoonConditions, + condition lagoonv1alpha1.LagoonBuildConditions, log []byte, ) error { // set the transition time condition.LastTransitionTime = time.Now().UTC().Format(time.RFC3339) - if !jobContainsStatus(lagoonBuild.Status.Conditions, condition) { + if !buildContainsStatus(lagoonBuild.Status.Conditions, condition) { lagoonBuild.Status.Conditions = append(lagoonBuild.Status.Conditions, condition) mergePatch, _ := json.Marshal(map[string]interface{}{ "status": map[string]interface{}{ diff --git a/controllers/lagoonmonitor_buildhandlers.go b/controllers/lagoonmonitor_buildhandlers.go index 481f5dca..85042142 100644 --- a/controllers/lagoonmonitor_buildhandlers.go +++ b/controllers/lagoonmonitor_buildhandlers.go @@ -76,7 +76,7 @@ func (r *LagoonMonitorReconciler) handleBuildMonitor(ctx context.Context, }, } jobPod.Status.ContainerStatuses[0] = state - r.updateBuildStatusCondition(ctx, &lagoonBuild, lagoonv1alpha1.LagoonConditions{ + r.updateBuildStatusCondition(ctx, &lagoonBuild, lagoonv1alpha1.LagoonBuildConditions{ Type: lagoonv1alpha1.BuildStatusFailed, Status: corev1.ConditionTrue, }, []byte(container.State.Waiting.Message)) @@ -373,12 +373,12 @@ func (r *LagoonMonitorReconciler) buildStatusLogsToLagoonLogs(ctx context.Contex // updateBuildStatusCondition is used to patch the lagoon build with the status conditions for the build, plus any logs func (r *LagoonMonitorReconciler) updateBuildStatusCondition(ctx context.Context, lagoonBuild *lagoonv1alpha1.LagoonBuild, - condition lagoonv1alpha1.LagoonConditions, + condition lagoonv1alpha1.LagoonBuildConditions, log []byte, ) error { // set the transition time condition.LastTransitionTime = time.Now().UTC().Format(time.RFC3339) - if !jobContainsStatus(lagoonBuild.Status.Conditions, condition) { + if !buildContainsStatus(lagoonBuild.Status.Conditions, condition) { lagoonBuild.Status.Conditions = append(lagoonBuild.Status.Conditions, condition) mergePatch, _ := json.Marshal(map[string]interface{}{ "status": map[string]interface{}{ @@ -544,7 +544,7 @@ Build cancelled if err := r.Patch(ctx, &lagoonBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { opLog.Error(err, fmt.Sprintf("Unable to update resource")) } - r.updateBuildStatusCondition(ctx, &lagoonBuild, lagoonv1alpha1.LagoonConditions{ + r.updateBuildStatusCondition(ctx, &lagoonBuild, lagoonv1alpha1.LagoonBuildConditions{ Type: jobCondition, Status: corev1.ConditionTrue, }, allContainerLogs) diff --git a/controllers/lagoonmonitor_taskhandlers.go b/controllers/lagoonmonitor_taskhandlers.go index 41271b7d..aed87d01 100644 --- a/controllers/lagoonmonitor_taskhandlers.go +++ b/controllers/lagoonmonitor_taskhandlers.go @@ -33,11 +33,11 @@ func (r *LagoonMonitorReconciler) handleTaskMonitor(ctx context.Context, opLog l if container.State.Waiting != nil && containsString(failureStates, container.State.Waiting.Reason) { // if we have a failure state, then fail the build and get the logs from the container opLog.Info(fmt.Sprintf("Task failed, container exit reason was: %v", container.State.Waiting.Reason)) - lagoonTask.Labels["lagoon.sh/taskStatus"] = string(lagoonv1alpha1.BuildStatusFailed) + lagoonTask.Labels["lagoon.sh/taskStatus"] = string(lagoonv1alpha1.TaskStatusFailed) if err := r.Update(ctx, &lagoonTask); err != nil { return err } - opLog.Info(fmt.Sprintf("Marked task %s as %s", lagoonTask.ObjectMeta.Name, string(lagoonv1alpha1.BuildStatusFailed))) + opLog.Info(fmt.Sprintf("Marked task %s as %s", lagoonTask.ObjectMeta.Name, string(lagoonv1alpha1.TaskStatusFailed))) if err := r.Delete(ctx, &jobPod); err != nil { return err } @@ -53,8 +53,8 @@ func (r *LagoonMonitorReconciler) handleTaskMonitor(ctx context.Context, opLog l }, } jobPod.Status.ContainerStatuses[0] = state - r.updateTaskStatusCondition(ctx, &lagoonTask, lagoonv1alpha1.LagoonConditions{ - Type: lagoonv1alpha1.BuildStatusFailed, + r.updateTaskStatusCondition(ctx, &lagoonTask, lagoonv1alpha1.LagoonTaskConditions{ + Type: lagoonv1alpha1.TaskStatusFailed, Status: corev1.ConditionTrue, }, []byte(container.State.Waiting.Message)) // send any messages to lagoon message queues @@ -76,12 +76,12 @@ func (r *LagoonMonitorReconciler) handleTaskMonitor(ctx context.Context, opLog l if err != nil { return err } - var jobCondition lagoonv1alpha1.BuildStatusType + var jobCondition lagoonv1alpha1.TaskStatusType switch jobPod.Status.Phase { case corev1.PodFailed: - jobCondition = lagoonv1alpha1.BuildStatusFailed + jobCondition = lagoonv1alpha1.TaskStatusFailed case corev1.PodSucceeded: - jobCondition = lagoonv1alpha1.BuildStatusComplete + jobCondition = lagoonv1alpha1.TaskStatusComplete } // if the build status doesn't equal the status of the pod // then update the build to reflect the current pod status @@ -106,7 +106,7 @@ func (r *LagoonMonitorReconciler) handleTaskMonitor(ctx context.Context, opLog l return err } r.updateTaskStatusCondition(ctx, &lagoonTask, - lagoonv1alpha1.LagoonConditions{ + lagoonv1alpha1.LagoonTaskConditions{ Type: jobCondition, Status: corev1.ConditionTrue, }, @@ -299,10 +299,10 @@ func (r *LagoonMonitorReconciler) taskStatusLogsToLagoonLogs(opLog logr.Logger, // updateTaskStatusCondition is used to patch the lagoon build with the status conditions for the build, plus any logs func (r *LagoonMonitorReconciler) updateTaskStatusCondition(ctx context.Context, lagoonTask *lagoonv1alpha1.LagoonTask, - condition lagoonv1alpha1.LagoonConditions, log []byte) error { + condition lagoonv1alpha1.LagoonTaskConditions, log []byte) error { // set the transition time condition.LastTransitionTime = time.Now().UTC().Format(time.RFC3339) - if !jobContainsStatus(lagoonTask.Status.Conditions, condition) { + if !taskContainsStatus(lagoonTask.Status.Conditions, condition) { lagoonTask.Status.Conditions = append(lagoonTask.Status.Conditions, condition) mergePatch, _ := json.Marshal(map[string]interface{}{ "status": map[string]interface{}{ diff --git a/controllers/lagoontask_controller.go b/controllers/lagoontask_controller.go index c579fd38..89d5af5c 100644 --- a/controllers/lagoontask_controller.go +++ b/controllers/lagoontask_controller.go @@ -75,10 +75,12 @@ func (r *LagoonTaskReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) // examine DeletionTimestamp to determine if object is under deletion if lagoonTask.ObjectMeta.DeletionTimestamp.IsZero() { // check if the task that has been recieved is a standard or advanced task - if lagoonTask.ObjectMeta.Labels["lagoon.sh/taskStatus"] == "Pending" && lagoonTask.ObjectMeta.Labels["lagoon.sh/taskType"] == "standard" { + if lagoonTask.ObjectMeta.Labels["lagoon.sh/taskStatus"] == string(lagoonv1alpha1.TaskStatusPending) && + lagoonTask.ObjectMeta.Labels["lagoon.sh/taskType"] == string(lagoonv1alpha1.TaskTypeStandard) { return ctrl.Result{}, r.createStandardTask(ctx, &lagoonTask, opLog) } - if lagoonTask.ObjectMeta.Labels["lagoon.sh/taskStatus"] == "Pending" && lagoonTask.ObjectMeta.Labels["lagoon.sh/taskType"] == "advanced" { + if lagoonTask.ObjectMeta.Labels["lagoon.sh/taskStatus"] == string(lagoonv1alpha1.TaskStatusPending) && + lagoonTask.ObjectMeta.Labels["lagoon.sh/taskType"] == string(lagoonv1alpha1.TaskTypeAdvanced) { return ctrl.Result{}, r.createAdvancedTask(ctx, &lagoonTask, opLog) } } else { diff --git a/handlers/helpers.go b/handlers/helpers.go index 8676450d..6caba1e4 100644 --- a/handlers/helpers.go +++ b/handlers/helpers.go @@ -23,17 +23,28 @@ const ( ) var ( - // RunningPendingStatus . - RunningPendingStatus = []string{ + // BuildRunningPendingStatus . + BuildRunningPendingStatus = []string{ string(lagoonv1alpha1.BuildStatusPending), string(lagoonv1alpha1.BuildStatusRunning), } - // CompletedCancelledFailedStatus . - CompletedCancelledFailedStatus = []string{ + // BuildCompletedCancelledFailedStatus . + BuildCompletedCancelledFailedStatus = []string{ string(lagoonv1alpha1.BuildStatusFailed), string(lagoonv1alpha1.BuildStatusComplete), string(lagoonv1alpha1.BuildStatusCancelled), } + // TaskRunningPendingStatus . + TaskRunningPendingStatus = []string{ + string(lagoonv1alpha1.TaskStatusPending), + string(lagoonv1alpha1.TaskStatusRunning), + } + // TaskCompletedCancelledFailedStatus . + TaskCompletedCancelledFailedStatus = []string{ + string(lagoonv1alpha1.TaskStatusFailed), + string(lagoonv1alpha1.TaskStatusComplete), + string(lagoonv1alpha1.TaskStatusCancelled), + } ) // ignoreNotFound will ignore not found errors @@ -65,7 +76,16 @@ func removeString(slice []string, s string) (result []string) { return } -func jobContainsStatus(slice []lagoonv1alpha1.LagoonConditions, s lagoonv1alpha1.LagoonConditions) bool { +func buildContainsStatus(slice []lagoonv1alpha1.LagoonBuildConditions, s lagoonv1alpha1.LagoonBuildConditions) bool { + for _, item := range slice { + if item == s { + return true + } + } + return false +} + +func taskContainsStatus(slice []lagoonv1alpha1.LagoonTaskConditions, s lagoonv1alpha1.LagoonTaskConditions) bool { for _, item := range slice { if item == s { return true diff --git a/handlers/message_queue.go b/handlers/message_queue.go index e83e6e57..b5f93141 100644 --- a/handlers/message_queue.go +++ b/handlers/message_queue.go @@ -273,8 +273,8 @@ func (h *Messaging) Consumer(targetName string) { //error { job.ObjectMeta.Namespace = job.Spec.Environment.OpenshiftProjectName job.SetLabels( map[string]string{ - "lagoon.sh/taskType": "standard", - "lagoon.sh/taskStatus": "Pending", + "lagoon.sh/taskType": string(lagoonv1alpha1.TaskTypeStandard), + "lagoon.sh/taskStatus": string(lagoonv1alpha1.TaskStatusPending), "lagoon.sh/controller": h.ControllerNamespace, }, ) diff --git a/handlers/misctask_handler.go b/handlers/misctask_handler.go index 84c4085b..fc5bb9f5 100644 --- a/handlers/misctask_handler.go +++ b/handlers/misctask_handler.go @@ -141,8 +141,8 @@ func createAdvancedTask(jobSpec *lagoonv1alpha1.LagoonTaskSpec, h *Messaging) er Name: "lagoon-advanced-task-" + randString(6), Namespace: jobSpec.Environment.OpenshiftProjectName, Labels: map[string]string{ - "lagoon.sh/taskType": "advanced", - "lagoon.sh/taskStatus": "Pending", + "lagoon.sh/taskType": string(lagoonv1alpha1.TaskTypeAdvanced), + "lagoon.sh/taskStatus": string(lagoonv1alpha1.TaskStatusPending), "lagoon.sh/controller": h.ControllerNamespace, }, }, diff --git a/handlers/resource_cleanup.go b/handlers/resource_cleanup.go index 9198c55a..9459c163 100644 --- a/handlers/resource_cleanup.go +++ b/handlers/resource_cleanup.go @@ -24,6 +24,7 @@ type cleanup interface { type Cleanup struct { Client client.Client BuildsToKeep int + TasksToKeep int BuildPodsToKeep int TaskPodsToKeep int ControllerNamespace string @@ -31,10 +32,11 @@ type Cleanup struct { } // NewCleanup returns a cleanup with controller-runtime client. -func NewCleanup(client client.Client, buildsToKeep int, buildPodsToKeep int, taskPodsToKeep int, controllerNamespace string, enableDebug bool) *Cleanup { +func NewCleanup(client client.Client, buildsToKeep int, buildPodsToKeep int, tasksToKeep int, taskPodsToKeep int, controllerNamespace string, enableDebug bool) *Cleanup { return &Cleanup{ Client: client, BuildsToKeep: buildsToKeep, + TasksToKeep: tasksToKeep, BuildPodsToKeep: buildPodsToKeep, TaskPodsToKeep: taskPodsToKeep, ControllerNamespace: controllerNamespace, @@ -78,7 +80,7 @@ func (h *Cleanup) LagoonBuildCleanup() { for idx, lagoonBuild := range lagoonBuilds.Items { if idx >= h.BuildsToKeep { if containsString( - CompletedCancelledFailedStatus, + BuildCompletedCancelledFailedStatus, lagoonBuild.ObjectMeta.Annotations["lagoon.sh/buildStatus"], ) { opLog.Info(fmt.Sprintf("Cleaning up LagoonBuild %s", lagoonBuild.ObjectMeta.Name)) @@ -94,6 +96,58 @@ func (h *Cleanup) LagoonBuildCleanup() { return } +// LagoonTaskCleanup will clean up any build crds that are hanging around. +func (h *Cleanup) LagoonTaskCleanup() { + opLog := ctrl.Log.WithName("handlers").WithName("LagoonTaskCleanup") + namespaces := &corev1.NamespaceList{} + labelRequirements, _ := labels.NewRequirement("lagoon.sh/environmentType", selection.Exists, nil) + listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ + client.MatchingLabelsSelector{ + Selector: labels.NewSelector().Add(*labelRequirements), + }, + }) + if err := h.Client.List(context.Background(), namespaces, listOption); err != nil { + opLog.Error(err, fmt.Sprintf("Unable to list namespaces created by Lagoon, there may be none or something went wrong")) + return + } + for _, ns := range namespaces.Items { + opLog.Info(fmt.Sprintf("Checking LagoonTasks in namespace %s", ns.ObjectMeta.Name)) + lagoonTasks := &lagoonv1alpha1.LagoonTaskList{} + listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ + client.InNamespace(ns.ObjectMeta.Name), + client.MatchingLabels(map[string]string{ + "lagoon.sh/jobType": "task", + "lagoon.sh/controller": h.ControllerNamespace, // created by this controller + }), + }) + if err := h.Client.List(context.Background(), lagoonTasks, listOption); err != nil { + opLog.Error(err, fmt.Sprintf("Unable to list LagoonTask resources, there may be none or something went wrong")) + return + } + // sort the build pods by creation timestamp + sort.Slice(lagoonTasks.Items, func(i, j int) bool { + return lagoonTasks.Items[i].ObjectMeta.CreationTimestamp.After(lagoonTasks.Items[j].ObjectMeta.CreationTimestamp.Time) + }) + if len(lagoonTasks.Items) > h.TasksToKeep { + for idx, lagoonTask := range lagoonTasks.Items { + if idx >= h.TasksToKeep { + if containsString( + TaskCompletedCancelledFailedStatus, + lagoonTask.ObjectMeta.Annotations["lagoon.sh/buildStatus"], + ) { + opLog.Info(fmt.Sprintf("Cleaning up LagoonTask %s", lagoonTask.ObjectMeta.Name)) + if err := h.Client.Delete(context.Background(), &lagoonTask); err != nil { + opLog.Error(err, fmt.Sprintf("Unable to update status condition")) + break + } + } + } + } + } + } + return +} + // BuildPodCleanup will clean up any build pods that are hanging around. func (h *Cleanup) BuildPodCleanup() { opLog := ctrl.Log.WithName("handlers").WithName("BuildPodCleanup") diff --git a/main.go b/main.go index 0f8bbf4e..7cf1771e 100644 --- a/main.go +++ b/main.go @@ -102,11 +102,14 @@ func main() { var buildPodCleanUpEnable bool var taskPodCleanUpEnable bool var buildsCleanUpEnable bool + var taskCleanUpEnable bool var buildPodCleanUpCron string var taskPodCleanUpCron string var buildsCleanUpCron string + var taskCleanUpCron string var buildsToKeep int var buildPodsToKeep int + var tasksToKeep int var taskPodsToKeep int var lffBackupWeeklyRandom bool var lffHarborEnabled bool @@ -212,6 +215,10 @@ func main() { flag.BoolVar(&taskPodCleanUpEnable, "enable-task-pod-cleanup", true, "Flag to enable build pod cleanup.") flag.StringVar(&taskPodCleanUpCron, "task-pod-cleanup-cron", "30 * * * *", "The cron definition for how often to run the task pod cleanup.") + flag.BoolVar(&taskCleanUpEnable, "enable-lagoontasks-cleanup", true, "Flag to enable lagoontask resources cleanup.") + flag.StringVar(&taskCleanUpCron, "lagoontasks-cleanup-cron", "0 * * * *", + "The cron definition for how often to run the lagoontask resources cleanup.") + flag.IntVar(&tasksToKeep, "num-tasks-to-keep", 5, "The number of lagoontask resources to keep per namespace.") flag.IntVar(&taskPodsToKeep, "num-task-pods-to-keep", 1, "The number of task pods to keep per namespace.") flag.BoolVar(&lffBackupWeeklyRandom, "lffBackupWeeklyRandom", false, "Tells Lagoon whether or not to use the \"weekly-random\" schedule for k8up backups.") @@ -513,6 +520,7 @@ func main() { resourceCleanup := handlers.NewCleanup(mgr.GetClient(), buildsToKeep, buildPodsToKeep, + tasksToKeep, taskPodsToKeep, controllerNamespace, enableDebug, @@ -535,6 +543,15 @@ func main() { resourceCleanup.BuildPodCleanup() }) } + // if the lagoontask cleanup is enabled, add the cronjob for it + if taskCleanUpEnable { + setupLog.Info("starting LagoonTask CRD cleanup handler") + // use cron to run a lagoontask cleanup task + // this will check any Lagoon tasks and attempt to delete them + c.AddFunc(taskCleanUpCron, func() { + resourceCleanup.LagoonTaskCleanup() + }) + } // if the task pod cleanup is enabled, add the cronjob for it if taskPodCleanUpEnable { setupLog.Info("starting task pod cleanup handler") From 4692a8332c9f537e53d106934a73b509b02e16c3 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Fri, 1 Oct 2021 15:28:47 +1000 Subject: [PATCH 19/35] chore: add support for native cron pod minimum frequency --- controllers/lagoonbuild_controller.go | 1 + controllers/lagoonbuild_helpers.go | 4 ++++ main.go | 16 ++++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/controllers/lagoonbuild_controller.go b/controllers/lagoonbuild_controller.go index c8ca819f..dde5834f 100644 --- a/controllers/lagoonbuild_controller.go +++ b/controllers/lagoonbuild_controller.go @@ -69,6 +69,7 @@ type LagoonBuildReconciler struct { Harbor Harbor LFFQoSEnabled bool BuildQoS BuildQoS + NativeCronPodMinFrequency int } // +kubebuilder:rbac:groups=lagoon.amazee.io,resources=lagoonbuilds,verbs=get;list;watch;create;update;patch;delete diff --git a/controllers/lagoonbuild_helpers.go b/controllers/lagoonbuild_helpers.go index 4c818dd9..457b908c 100644 --- a/controllers/lagoonbuild_helpers.go +++ b/controllers/lagoonbuild_helpers.go @@ -489,6 +489,10 @@ func (r *LagoonBuildReconciler) processBuild(ctx context.Context, opLog logr.Log Name: "K8UP_WEEKLY_RANDOM_FEATURE_FLAG", Value: strconv.FormatBool(r.LFFBackupWeeklyRandom), }, + { + Name: "NATIVE_CRON_POD_MINIMUM_FREQUENCY", + Value: strconv.Itoa(r.NativeCronPodMinFrequency), + }, } if r.IsOpenshift { // openshift builds have different names for some things, and also additional values to add diff --git a/main.go b/main.go index 7cf1771e..5be870b5 100644 --- a/main.go +++ b/main.go @@ -126,6 +126,7 @@ func main() { var harborCredentialCron string var harborLagoonWebhook string var harborWebhookEventTypes string + var nativeCronPodMinFrequency int var lffQoSEnabled bool var qosMaxBuilds int @@ -223,6 +224,8 @@ func main() { flag.BoolVar(&lffBackupWeeklyRandom, "lffBackupWeeklyRandom", false, "Tells Lagoon whether or not to use the \"weekly-random\" schedule for k8up backups.") + flag.IntVar(&nativeCronPodMinFrequency, "native-cron-pod-min-frequency", 15, "The number of lagoontask resources to keep per namespace.") + // harbor configurations flag.BoolVar(&lffHarborEnabled, "enable-harbor", false, "Flag to enable this controller to talk to a specific harbor.") flag.StringVar(&harborURL, "harbor-url", "harbor.172.17.0.1.nip.io:32080", @@ -288,6 +291,8 @@ func main() { lagoonSSHHost = getEnv("TASK_SSH_HOST", lagoonSSHHost) lagoonSSHPort = getEnv("TASK_SSH_PORT", lagoonSSHPort) + nativeCronPodMinFrequency = getEnvInt("NATIVE_CRON_POD_MINIMUM_FREQUENCY", nativeCronPodMinFrequency) + // harbor envvars harborURL = getEnv("HARBOR_URL", harborURL) harborAPI = getEnv("HARBOR_API", harborAPI) @@ -606,6 +611,7 @@ func main() { Harbor: harborConfig, LFFQoSEnabled: lffQoSEnabled, BuildQoS: buildQoSConfig, + NativeCronPodMinFrequency: nativeCronPodMinFrequency, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "LagoonBuild") os.Exit(1) @@ -654,6 +660,16 @@ func getEnv(key, fallback string) string { return fallback } +func getEnvInt(key string, fallback int) int { + if value, ok := os.LookupEnv(key); ok { + valueInt, e := strconv.Atoi(value) + if e == nil { + return valueInt + } + } + return fallback +} + // accepts fallback values 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False // anything else is false. func getEnvBool(key string, fallback bool) bool { From 18637a366391d45ea6a869628143a6a889fa321a Mon Sep 17 00:00:00 2001 From: Tim Clifford Date: Mon, 11 Oct 2021 17:24:51 +0100 Subject: [PATCH 20/35] adding lagoon env vars to adv task --- controllers/lagoontask_controller.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/controllers/lagoontask_controller.go b/controllers/lagoontask_controller.go index 89d5af5c..400d5290 100644 --- a/controllers/lagoontask_controller.go +++ b/controllers/lagoontask_controller.go @@ -482,6 +482,14 @@ func (r *LagoonTaskReconciler) createAdvancedTask(ctx context.Context, lagoonTas Name: "PODNAME", Value: lagoonTask.ObjectMeta.Name, }, + { + Name: "LAGOON_PROJECT", + Value: lagoonTask.Spec.Project.Name, + }, + { + Name: "LAGOON_GIT_BRANCH", + Value: lagoonTask.Spec.Environment.Name, + }, { Name: "TASK_API_HOST", Value: r.getTaskValue(lagoonTask, "TASK_API_HOST"), From ca306e6a8cc02a71913fbd27a0b025bba1292e10 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 13 Oct 2021 13:56:47 +1100 Subject: [PATCH 21/35] fix: wrong annotation --- handlers/resource_cleanup.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/handlers/resource_cleanup.go b/handlers/resource_cleanup.go index 9459c163..9dd095e7 100644 --- a/handlers/resource_cleanup.go +++ b/handlers/resource_cleanup.go @@ -133,7 +133,7 @@ func (h *Cleanup) LagoonTaskCleanup() { if idx >= h.TasksToKeep { if containsString( TaskCompletedCancelledFailedStatus, - lagoonTask.ObjectMeta.Annotations["lagoon.sh/buildStatus"], + lagoonTask.ObjectMeta.Annotations["lagoon.sh/taskStatus"], ) { opLog.Info(fmt.Sprintf("Cleaning up LagoonTask %s", lagoonTask.ObjectMeta.Name)) if err := h.Client.Delete(context.Background(), &lagoonTask); err != nil { From 20598c278ba5e7b3dfc7cc43faef05c97f20a07f Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 13 Oct 2021 18:59:50 +1100 Subject: [PATCH 22/35] chore: send task logs as `task-logs` events, and also add the environment name to the log meta --- controllers/lagoonmonitor_taskhandlers.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/controllers/lagoonmonitor_taskhandlers.go b/controllers/lagoonmonitor_taskhandlers.go index aed87d01..62b6d5ed 100644 --- a/controllers/lagoonmonitor_taskhandlers.go +++ b/controllers/lagoonmonitor_taskhandlers.go @@ -148,13 +148,14 @@ func (r *LagoonMonitorReconciler) taskLogsToLagoonLogs(opLog logr.Logger, msg := lagoonv1alpha1.LagoonLog{ Severity: "info", Project: lagoonTask.Spec.Project.Name, - Event: "build-logs:job-kubernetes:" + lagoonTask.ObjectMeta.Name, + Event: "task-logs:job-kubernetes:" + lagoonTask.ObjectMeta.Name, Meta: &lagoonv1alpha1.LagoonLogMeta{ - Task: &lagoonTask.Spec.Task, - JobName: lagoonTask.ObjectMeta.Name, - JobStatus: condition, - RemoteID: string(jobPod.ObjectMeta.UID), - Key: lagoonTask.Spec.Key, + Task: &lagoonTask.Spec.Task, + Environment: lagoonTask.Spec.Environment.Name, + JobName: lagoonTask.ObjectMeta.Name, + JobStatus: condition, + RemoteID: string(jobPod.ObjectMeta.UID), + Key: lagoonTask.Spec.Key, }, Message: fmt.Sprintf(`======================================== Logs on pod %s From aab6f5154c611e17ffe473e846bc404e89d859ee Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Mon, 25 Oct 2021 10:09:55 +1100 Subject: [PATCH 23/35] feat: support for shipping logs if the pod status is running --- controllers/lagoonmonitor_buildhandlers.go | 41 ++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/controllers/lagoonmonitor_buildhandlers.go b/controllers/lagoonmonitor_buildhandlers.go index 85042142..bf0dc029 100644 --- a/controllers/lagoonmonitor_buildhandlers.go +++ b/controllers/lagoonmonitor_buildhandlers.go @@ -99,6 +99,22 @@ func (r *LagoonMonitorReconciler) handleBuildMonitor(ctx context.Context, } } return nil + } else if jobPod.Status.Phase == corev1.PodRunning { + // if the pod is running and detects a change to the pod (eg, detecting an updated lagoon.sh/buildStep label) + // then ship or store the logs + opLog.Info(fmt.Sprintf("Build %s is %v", jobPod.ObjectMeta.Labels["lagoon.sh/buildName"], jobPod.Status.Phase)) + // get the build associated to this pod, the information in the resource is used for shipping the logs + var lagoonBuild lagoonv1alpha1.LagoonBuild + err := r.Get(ctx, + types.NamespacedName{ + Namespace: jobPod.ObjectMeta.Namespace, + Name: jobPod.ObjectMeta.Labels["lagoon.sh/buildName"], + }, &lagoonBuild) + if err != nil { + return err + } + // actually run the log collection and shipping function + r.updateRunningDeploymentBuildLogs(ctx, req, lagoonBuild, jobPod) } // if the buildpod status is failed or succeeded // mark the build accordingly and ship the information back to lagoon @@ -483,6 +499,31 @@ func (r *LagoonMonitorReconciler) removeBuildPendingMessageStatus(ctx context.Co return nil } +// updateRunningDeploymentBuildLogs collects logs from running build containers and ships or stores them +func (r *LagoonMonitorReconciler) updateRunningDeploymentBuildLogs( + ctx context.Context, + req ctrl.Request, + lagoonBuild lagoonv1alpha1.LagoonBuild, + jobPod corev1.Pod, +) { + opLog := r.Log.WithValues("lagoonmonitor", req.NamespacedName) + var allContainerLogs []byte + // grab all the logs from the containers in the build pod and just merge them all together + // we only have 1 container at the moment in a buildpod anyway so it doesn't matter + // if we do move to multi container builds, then worry about it + for _, container := range jobPod.Spec.Containers { + cLogs, err := getContainerLogs(container.Name, req) + if err != nil { + opLog.Error(err, fmt.Sprintf("Unable to retrieve logs from build pod")) + // log the error, but just continue + } + allContainerLogs = append(allContainerLogs, cLogs...) + } + // send any messages to lagoon message queues + r.buildLogsToLagoonLogs(ctx, opLog, &lagoonBuild, &jobPod, allContainerLogs) +} + +// updateDeploymentWithLogs collects logs from the build containers and ships or stores them func (r *LagoonMonitorReconciler) updateDeploymentWithLogs( ctx context.Context, req ctrl.Request, From d339f95fded82bfbcb9cebf599af19d99de16ed6 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Mon, 25 Oct 2021 12:37:35 +1100 Subject: [PATCH 24/35] feat: add labels for idling to namespaces --- api/v1alpha1/lagoonbuild_types.go | 2 ++ api/v1alpha1/zz_generated.deepcopy.go | 10 ++++++++++ config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml | 4 ++++ controllers/lagoonbuild_helpers.go | 7 +++++++ 4 files changed, 23 insertions(+) diff --git a/api/v1alpha1/lagoonbuild_types.go b/api/v1alpha1/lagoonbuild_types.go index 5aa1ec1e..b53f1737 100644 --- a/api/v1alpha1/lagoonbuild_types.go +++ b/api/v1alpha1/lagoonbuild_types.go @@ -127,6 +127,8 @@ type Project struct { Monitoring Monitoring `json:"monitoring"` Variables Variables `json:"variables"` Registry string `json:"registry,omitempty"` + EnvironmentIdling *int `json:"environmentIdling,omitempty"` + ProjectIdling *int `json:"projectIdling,omitempty"` } // Variables contains the project and environment variables from lagoon. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index b554f721..df53ce5b 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -564,6 +564,16 @@ func (in *Project) DeepCopyInto(out *Project) { } out.Monitoring = in.Monitoring in.Variables.DeepCopyInto(&out.Variables) + if in.EnvironmentIdling != nil { + in, out := &in.EnvironmentIdling, &out.EnvironmentIdling + *out = new(int) + **out = **in + } + if in.ProjectIdling != nil { + in, out := &in.ProjectIdling, &out.ProjectIdling + *out = new(int) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Project. diff --git a/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml b/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml index 141985bd..13e82e06 100644 --- a/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml +++ b/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml @@ -68,6 +68,8 @@ spec: type: string environmentId: type: integer + environmentIdling: + type: integer environmentType: type: string gitUrl: @@ -92,6 +94,8 @@ spec: type: string productionEnvironment: type: string + projectIdling: + type: integer projectSecret: type: string registry: diff --git a/controllers/lagoonbuild_helpers.go b/controllers/lagoonbuild_helpers.go index 457b908c..029b2596 100644 --- a/controllers/lagoonbuild_helpers.go +++ b/controllers/lagoonbuild_helpers.go @@ -143,6 +143,13 @@ func (r *LagoonBuildReconciler) getOrCreateNamespace(ctx context.Context, namesp if spec.Project.EnvironmentID != nil { nsLabels["lagoon.sh/environmentId"] = fmt.Sprintf("%d", *spec.Project.EnvironmentID) } + // set the auto idling values if they are defined + if spec.Project.EnvironmentIdling != nil { + nsLabels["lagoon.sh/environmentAutoIdle"] = fmt.Sprintf("%d", *spec.Project.EnvironmentIdling) + } + if spec.Project.ProjectIdling != nil { + nsLabels["lagoon.sh/projectAutoIdle"] = fmt.Sprintf("%d", *spec.Project.ProjectIdling) + } // if it isn't an openshift build, then just create a normal namespace // add the required lagoon labels to the namespace when creating namespace.ObjectMeta = metav1.ObjectMeta{ From 1cb0f9498a1f2a57ef664320727f8c08ac4409b6 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 28 Oct 2021 09:20:58 +1100 Subject: [PATCH 25/35] feat: cancel builds if namespaces are being terminated --- controllers/lagoon_harborintegration.go | 5 ++ controllers/lagoonbuild_controller.go | 2 +- controllers/lagoonbuild_deletionhandlers.go | 22 ++--- controllers/lagoonbuild_helpers.go | 95 +++++++++++++++++---- handlers/resource_cleanup.go | 20 +++++ 5 files changed, 117 insertions(+), 27 deletions(-) diff --git a/controllers/lagoon_harborintegration.go b/controllers/lagoon_harborintegration.go index 78012ae5..a170ff4d 100644 --- a/controllers/lagoon_harborintegration.go +++ b/controllers/lagoon_harborintegration.go @@ -330,6 +330,11 @@ func (h *Harbor) RotateRobotCredentials(ctx context.Context, cl client.Client) { // go over every namespace that has a lagoon.sh label // and attempt to create and update the robot account credentials as requred. for _, ns := range namespaces.Items { + if ns.Status.Phase == corev1.NamespaceTerminating { + // if the namespace is terminating, don't try to renew the robot credentials + opLog.Info(fmt.Sprintf("Namespace %s is being terminated, aborting robot credentials check", ns.ObjectMeta.Name)) + return + } opLog.Info(fmt.Sprintf("Checking if %s needs robot credentials rotated", ns.ObjectMeta.Name)) // check for running builds! lagoonBuilds := &lagoonv1alpha1.LagoonBuildList{} diff --git a/controllers/lagoonbuild_controller.go b/controllers/lagoonbuild_controller.go index dde5834f..3a2eb152 100644 --- a/controllers/lagoonbuild_controller.go +++ b/controllers/lagoonbuild_controller.go @@ -170,7 +170,7 @@ func (r *LagoonBuildReconciler) createNamespaceBuild(ctx context.Context, namespace := &corev1.Namespace{} opLog.Info(fmt.Sprintf("Checking Namespace exists for: %s", lagoonBuild.ObjectMeta.Name)) - err := r.getOrCreateNamespace(ctx, namespace, lagoonBuild.Spec) + err := r.getOrCreateNamespace(ctx, namespace, lagoonBuild, opLog) if err != nil { return ctrl.Result{}, err } diff --git a/controllers/lagoonbuild_deletionhandlers.go b/controllers/lagoonbuild_deletionhandlers.go index fb851ad3..d749df14 100644 --- a/controllers/lagoonbuild_deletionhandlers.go +++ b/controllers/lagoonbuild_deletionhandlers.go @@ -38,7 +38,7 @@ func (r *LagoonBuildReconciler) deleteExternalResources( opLog.Info(fmt.Sprintf("Unable to find a build pod associated to this build, continuing to process build deletion")) // handle updating lagoon for a deleted build with no running pod // only do it if the build status is Pending or Running though - err = r.updateDeploymentWithLogs(ctx, req, *lagoonBuild) + err = r.updateCancelledDeploymentWithLogs(ctx, req, *lagoonBuild) if err != nil { opLog.Error(err, fmt.Sprintf("Unable to update the lagoon with LagoonBuild result")) } @@ -152,7 +152,7 @@ func (r *LagoonBuildReconciler) deleteExternalResources( return nil } -func (r *LagoonBuildReconciler) updateDeploymentWithLogs( +func (r *LagoonBuildReconciler) updateCancelledDeploymentWithLogs( ctx context.Context, req ctrl.Request, lagoonBuild lagoonv1alpha1.LagoonBuild, @@ -213,16 +213,16 @@ Build cancelled } // send any messages to lagoon message queues // update the deployment with the status - r.buildStatusLogsToLagoonLogs(ctx, opLog, &lagoonBuild, &lagoonEnv) - r.updateDeploymentAndEnvironmentTask(ctx, opLog, &lagoonBuild, &lagoonEnv) - r.buildLogsToLagoonLogs(ctx, opLog, &lagoonBuild, allContainerLogs) + r.cancelledBuildStatusLogsToLagoonLogs(ctx, opLog, &lagoonBuild, &lagoonEnv) + r.updateCancelledDeploymentAndEnvironmentTask(ctx, opLog, &lagoonBuild, &lagoonEnv) + r.cancelledBuildLogsToLagoonLogs(ctx, opLog, &lagoonBuild, allContainerLogs) } return nil } -// buildLogsToLagoonLogs sends the build logs to the lagoon-logs message queue +// cancelledBuildLogsToLagoonLogs sends the build logs to the lagoon-logs message queue // it contains the actual pod log output that is sent to elasticsearch, it is what eventually is displayed in the UI -func (r *LagoonBuildReconciler) buildLogsToLagoonLogs(ctx context.Context, +func (r *LagoonBuildReconciler) cancelledBuildLogsToLagoonLogs(ctx context.Context, opLog logr.Logger, lagoonBuild *lagoonv1alpha1.LagoonBuild, logs []byte, @@ -266,9 +266,9 @@ Logs on pod %s } } -// updateDeploymentAndEnvironmentTask sends the status of the build and deployment to the controllerhandler message queue in lagoon, +// updateCancelledDeploymentAndEnvironmentTask sends the status of the build and deployment to the controllerhandler message queue in lagoon, // this is for the handler in lagoon to process. -func (r *LagoonBuildReconciler) updateDeploymentAndEnvironmentTask(ctx context.Context, +func (r *LagoonBuildReconciler) updateCancelledDeploymentAndEnvironmentTask(ctx context.Context, opLog logr.Logger, lagoonBuild *lagoonv1alpha1.LagoonBuild, lagoonEnv *corev1.ConfigMap, @@ -349,8 +349,8 @@ func (r *LagoonBuildReconciler) updateDeploymentAndEnvironmentTask(ctx context.C } } -// buildStatusLogsToLagoonLogs sends the logs to lagoon-logs message queue, used for general messaging -func (r *LagoonBuildReconciler) buildStatusLogsToLagoonLogs(ctx context.Context, +// cancelledBuildStatusLogsToLagoonLogs sends the logs to lagoon-logs message queue, used for general messaging +func (r *LagoonBuildReconciler) cancelledBuildStatusLogsToLagoonLogs(ctx context.Context, opLog logr.Logger, lagoonBuild *lagoonv1alpha1.LagoonBuild, lagoonEnv *corev1.ConfigMap) { diff --git a/controllers/lagoonbuild_helpers.go b/controllers/lagoonbuild_helpers.go index 457b908c..5b56d993 100644 --- a/controllers/lagoonbuild_helpers.go +++ b/controllers/lagoonbuild_helpers.go @@ -96,11 +96,11 @@ func (r *LagoonBuildReconciler) getOrCreateSARoleBinding(ctx context.Context, sa } // getOrCreateNamespace will create the namespace if it doesn't exist. -func (r *LagoonBuildReconciler) getOrCreateNamespace(ctx context.Context, namespace *corev1.Namespace, spec lagoonv1alpha1.LagoonBuildSpec) error { +func (r *LagoonBuildReconciler) getOrCreateNamespace(ctx context.Context, namespace *corev1.Namespace, lagoonBuild lagoonv1alpha1.LagoonBuild, opLog logr.Logger) error { // parse the project/env through the project pattern, or use the default var err error - nsPattern := spec.Project.NamespacePattern - if spec.Project.NamespacePattern == "" { + nsPattern := lagoonBuild.Spec.Project.NamespacePattern + if lagoonBuild.Spec.Project.NamespacePattern == "" { nsPattern = DefaultNamespacePattern } // lowercase and dnsify the namespace against the namespace pattern @@ -109,11 +109,11 @@ func (r *LagoonBuildReconciler) getOrCreateNamespace(ctx context.Context, namesp strings.Replace( nsPattern, "${environment}", - spec.Project.Environment, + lagoonBuild.Spec.Project.Environment, -1, ), "${project}", - spec.Project.Name, + lagoonBuild.Spec.Project.Name, -1, ), ) @@ -132,16 +132,16 @@ func (r *LagoonBuildReconciler) getOrCreateNamespace(ctx context.Context, namesp ns = fmt.Sprintf("%s-%s", ns[0:58], hashString(ns)[0:4]) } nsLabels := map[string]string{ - "lagoon.sh/project": spec.Project.Name, - "lagoon.sh/environment": spec.Project.Environment, - "lagoon.sh/environmentType": spec.Project.EnvironmentType, + "lagoon.sh/project": lagoonBuild.Spec.Project.Name, + "lagoon.sh/environment": lagoonBuild.Spec.Project.Environment, + "lagoon.sh/environmentType": lagoonBuild.Spec.Project.EnvironmentType, "lagoon.sh/controller": r.ControllerNamespace, } - if spec.Project.ID != nil { - nsLabels["lagoon.sh/projectId"] = fmt.Sprintf("%d", *spec.Project.ID) + if lagoonBuild.Spec.Project.ID != nil { + nsLabels["lagoon.sh/projectId"] = fmt.Sprintf("%d", *lagoonBuild.Spec.Project.ID) } - if spec.Project.EnvironmentID != nil { - nsLabels["lagoon.sh/environmentId"] = fmt.Sprintf("%d", *spec.Project.EnvironmentID) + if lagoonBuild.Spec.Project.EnvironmentID != nil { + nsLabels["lagoon.sh/environmentId"] = fmt.Sprintf("%d", *lagoonBuild.Spec.Project.EnvironmentID) } // if it isn't an openshift build, then just create a normal namespace // add the required lagoon labels to the namespace when creating @@ -149,12 +149,23 @@ func (r *LagoonBuildReconciler) getOrCreateNamespace(ctx context.Context, namesp Name: ns, Labels: nsLabels, } + + if err := r.Get(ctx, types.NamespacedName{Name: ns}, namespace); err != nil { + if ignoreNotFound(err) != nil { + return err + } + } + if namespace.Status.Phase == corev1.NamespaceTerminating { + r.cleanUpTerminatingNamespaceBuild(ctx, namespace, lagoonBuild, opLog) + return fmt.Errorf("%s is currently terminating, aborting build", ns) + } + // this is an openshift build, then we need to create a projectrequest // we use projectrequest so that we ensure any openshift specific things can happen. if r.IsOpenshift { projectRequest := &projectv1.ProjectRequest{} projectRequest.ObjectMeta.Name = ns - projectRequest.DisplayName = fmt.Sprintf(`[%s] %s`, spec.Project.Name, spec.Project.Environment) + projectRequest.DisplayName = fmt.Sprintf(`[%s] %s`, lagoonBuild.Spec.Project.Name, lagoonBuild.Spec.Project.Environment) if err := r.Get(ctx, types.NamespacedName{Name: ns}, namespace); err != nil { if err := r.Create(ctx, projectRequest); err != nil { return err @@ -204,7 +215,7 @@ func (r *LagoonBuildReconciler) getOrCreateNamespace(ctx context.Context, namesp return err } // create the project in harbor - hProject, err := lagoonHarbor.CreateProject(ctx, spec.Project.Name) + hProject, err := lagoonHarbor.CreateProject(ctx, lagoonBuild.Spec.Project.Name) if err != nil { return err } @@ -212,7 +223,7 @@ func (r *LagoonBuildReconciler) getOrCreateNamespace(ctx context.Context, namesp robotCreds, err := lagoonHarbor.CreateOrRefreshRobot(ctx, r.Client, hProject, - spec.Project.Environment, + lagoonBuild.Spec.Project.Environment, ns, time.Now().Add(lagoonHarbor.RobotAccountExpiry).Unix()) if err != nil { @@ -877,3 +888,57 @@ func (r *LagoonBuildReconciler) processBuild(ctx context.Context, opLog logr.Log opLog.Info(fmt.Sprintf("Build pod already running for: %s", lagoonBuild.ObjectMeta.Name)) return nil } + +// cleanUpTerminatingNamespaceBuild will clean up a build if the namespace is being terminated. +func (r *LagoonBuildReconciler) cleanUpTerminatingNamespaceBuild( + ctx context.Context, + namespace *corev1.Namespace, + lagoonBuild lagoonv1alpha1.LagoonBuild, + opLog logr.Logger, +) error { + var allContainerLogs []byte + // if we get this handler, then it is likely that the build was in a pending or running state with no actual running pod + // so just set the logs to be cancellation message + allContainerLogs = []byte(fmt.Sprintf(` +======================================== +Build cancelled +======================================== +Namespace is currently in terminating status - contact your Lagoon support team for help`)) + var jobCondition lagoonv1alpha1.BuildStatusType + jobCondition = lagoonv1alpha1.BuildStatusCancelled + lagoonBuild.Labels["lagoon.sh/buildStatus"] = string(jobCondition) + mergePatch, _ := json.Marshal(map[string]interface{}{ + "metadata": map[string]interface{}{ + "labels": map[string]interface{}{ + "lagoon.sh/buildStatus": string(jobCondition), + }, + }, + }) + if err := r.Patch(ctx, &lagoonBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + opLog.Error(err, fmt.Sprintf("Unable to update build status")) + } + // get the configmap for lagoon-env so we can use it for updating the deployment in lagoon + var lagoonEnv corev1.ConfigMap + err := r.Get(ctx, types.NamespacedName{ + Namespace: lagoonBuild.ObjectMeta.Namespace, + Name: "lagoon-env", + }, + &lagoonEnv, + ) + if err != nil { + // if there isn't a configmap, just info it and move on + // the updatedeployment function will see it as nil and not bother doing the bits that require the configmap + opLog.Info(fmt.Sprintf("There is no configmap %s in namespace %s ", "lagoon-env", lagoonBuild.ObjectMeta.Namespace)) + } + // send any messages to lagoon message queues + // update the deployment with the status + r.cancelledBuildStatusLogsToLagoonLogs(ctx, opLog, &lagoonBuild, &lagoonEnv) + r.updateCancelledDeploymentAndEnvironmentTask(ctx, opLog, &lagoonBuild, &lagoonEnv) + r.cancelledBuildLogsToLagoonLogs(ctx, opLog, &lagoonBuild, allContainerLogs) + // delete the build from the lagoon namespace in kubernetes entirely + err = r.Delete(ctx, &lagoonBuild) + if err != nil { + return err + } + return nil +} diff --git a/handlers/resource_cleanup.go b/handlers/resource_cleanup.go index 9dd095e7..c922e944 100644 --- a/handlers/resource_cleanup.go +++ b/handlers/resource_cleanup.go @@ -59,6 +59,11 @@ func (h *Cleanup) LagoonBuildCleanup() { return } for _, ns := range namespaces.Items { + if ns.Status.Phase == corev1.NamespaceTerminating { + // if the namespace is terminating, don't try to renew the robot credentials + opLog.Info(fmt.Sprintf("Namespace %s is being terminated, aborting task pod cleanup", ns.ObjectMeta.Name)) + return + } opLog.Info(fmt.Sprintf("Checking LagoonBuilds in namespace %s", ns.ObjectMeta.Name)) lagoonBuilds := &lagoonv1alpha1.LagoonBuildList{} listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ @@ -111,6 +116,11 @@ func (h *Cleanup) LagoonTaskCleanup() { return } for _, ns := range namespaces.Items { + if ns.Status.Phase == corev1.NamespaceTerminating { + // if the namespace is terminating, don't try to renew the robot credentials + opLog.Info(fmt.Sprintf("Namespace %s is being terminated, aborting task pod cleanup", ns.ObjectMeta.Name)) + return + } opLog.Info(fmt.Sprintf("Checking LagoonTasks in namespace %s", ns.ObjectMeta.Name)) lagoonTasks := &lagoonv1alpha1.LagoonTaskList{} listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ @@ -163,6 +173,11 @@ func (h *Cleanup) BuildPodCleanup() { return } for _, ns := range namespaces.Items { + if ns.Status.Phase == corev1.NamespaceTerminating { + // if the namespace is terminating, don't try to renew the robot credentials + opLog.Info(fmt.Sprintf("Namespace %s is being terminated, aborting task pod cleanup", ns.ObjectMeta.Name)) + return + } opLog.Info(fmt.Sprintf("Checking Lagoon build pods in namespace %s", ns.ObjectMeta.Name)) buildPods := &corev1.PodList{} listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ @@ -213,6 +228,11 @@ func (h *Cleanup) TaskPodCleanup() { return } for _, ns := range namespaces.Items { + if ns.Status.Phase == corev1.NamespaceTerminating { + // if the namespace is terminating, don't try to renew the robot credentials + opLog.Info(fmt.Sprintf("Namespace %s is being terminated, aborting task pod cleanup", ns.ObjectMeta.Name)) + return + } opLog.Info(fmt.Sprintf("Checking Lagoon task pods in namespace %s", ns.ObjectMeta.Name)) taskPods := &corev1.PodList{} listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ From d206737308dd56c70b7789e13d53f2d6190cf61d Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 28 Oct 2021 10:54:49 +1100 Subject: [PATCH 26/35] fix: fix up merge issue with reference change --- controllers/lagoonbuild_helpers.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/controllers/lagoonbuild_helpers.go b/controllers/lagoonbuild_helpers.go index e4192965..7f49ec30 100644 --- a/controllers/lagoonbuild_helpers.go +++ b/controllers/lagoonbuild_helpers.go @@ -144,11 +144,11 @@ func (r *LagoonBuildReconciler) getOrCreateNamespace(ctx context.Context, namesp nsLabels["lagoon.sh/environmentId"] = fmt.Sprintf("%d", *lagoonBuild.Spec.Project.EnvironmentID) } // set the auto idling values if they are defined - if spec.Project.EnvironmentIdling != nil { - nsLabels["lagoon.sh/environmentAutoIdle"] = fmt.Sprintf("%d", *spec.Project.EnvironmentIdling) + if lagoonBuild.Spec.Project.EnvironmentIdling != nil { + nsLabels["lagoon.sh/environmentAutoIdle"] = fmt.Sprintf("%d", *lagoonBuild.Spec.Project.EnvironmentIdling) } - if spec.Project.ProjectIdling != nil { - nsLabels["lagoon.sh/projectAutoIdle"] = fmt.Sprintf("%d", *spec.Project.ProjectIdling) + if lagoonBuild.Spec.Project.ProjectIdling != nil { + nsLabels["lagoon.sh/projectAutoIdle"] = fmt.Sprintf("%d", *lagoonBuild.Spec.Project.ProjectIdling) } // if it isn't an openshift build, then just create a normal namespace // add the required lagoon labels to the namespace when creating From 1511b7583ee624e4884ad4ca1c7c873920afec78 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 28 Oct 2021 11:35:10 +1100 Subject: [PATCH 27/35] feat: add flag to enable/disable support for generating the ROUTER_URL --- controllers/lagoonbuild_controller.go | 1 + controllers/lagoonbuild_helpers.go | 82 +++++++++++++++------------ main.go | 9 +++ 3 files changed, 56 insertions(+), 36 deletions(-) diff --git a/controllers/lagoonbuild_controller.go b/controllers/lagoonbuild_controller.go index 3a2eb152..7ff47aec 100644 --- a/controllers/lagoonbuild_controller.go +++ b/controllers/lagoonbuild_controller.go @@ -65,6 +65,7 @@ type LagoonBuildReconciler struct { BackupDefaultDailyRetention int BackupDefaultHourlyRetention int LFFBackupWeeklyRandom bool + LFFRouterURL bool LFFHarborEnabled bool Harbor Harbor LFFQoSEnabled bool diff --git a/controllers/lagoonbuild_helpers.go b/controllers/lagoonbuild_helpers.go index 7f49ec30..982f8166 100644 --- a/controllers/lagoonbuild_helpers.go +++ b/controllers/lagoonbuild_helpers.go @@ -530,22 +530,27 @@ func (r *LagoonBuildReconciler) processBuild(ctx context.Context, opLog logr.Log Name: "OPENSHIFT_NAME", Value: lagoonBuild.Spec.Project.DeployTarget, }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "ROUTER_URL", - Value: strings.ToLower( - strings.Replace( + // this is enabled by default for now + // eventually will be disabled by default because support for the generation/modification of this will + // be handled by lagoon or the builds themselves + if r.LFFRouterURL { + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "ROUTER_URL", + Value: strings.ToLower( strings.Replace( - lagoonBuild.Spec.Project.RouterPattern, - "${branch}", - lagoonBuild.Spec.Project.Environment, + strings.Replace( + lagoonBuild.Spec.Project.RouterPattern, + "${branch}", + lagoonBuild.Spec.Project.Environment, + -1, + ), + "${project}", + lagoonBuild.Spec.Project.Name, -1, ), - "${project}", - lagoonBuild.Spec.Project.Name, - -1, ), - ), - }) + }) + } } else { podEnvs = append(podEnvs, corev1.EnvVar{ Name: "BUILD_TYPE", @@ -563,38 +568,43 @@ func (r *LagoonBuildReconciler) processBuild(ctx context.Context, opLog logr.Log Name: "REGISTRY", Value: lagoonBuild.Spec.Project.Registry, }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "ROUTER_URL", - Value: strings.ToLower( - strings.Replace( + // this is enabled by default for now + // eventually will be disabled by default because support for the generation/modification of this will + // be handled by lagoon or the builds themselves + if r.LFFRouterURL { + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "ROUTER_URL", + Value: strings.ToLower( strings.Replace( - lagoonBuild.Spec.Project.RouterPattern, - "${environment}", - lagoonBuild.Spec.Project.Environment, + strings.Replace( + lagoonBuild.Spec.Project.RouterPattern, + "${environment}", + lagoonBuild.Spec.Project.Environment, + -1, + ), + "${project}", + lagoonBuild.Spec.Project.Name, -1, ), - "${project}", - lagoonBuild.Spec.Project.Name, - -1, ), - ), - }) - podEnvs = append(podEnvs, corev1.EnvVar{ - Name: "SHORT_ROUTER_URL", - Value: strings.ToLower( - strings.Replace( + }) + podEnvs = append(podEnvs, corev1.EnvVar{ + Name: "SHORT_ROUTER_URL", + Value: strings.ToLower( strings.Replace( - lagoonBuild.Spec.Project.RouterPattern, - "${environment}", - shortName(lagoonBuild.Spec.Project.Environment), + strings.Replace( + lagoonBuild.Spec.Project.RouterPattern, + "${environment}", + shortName(lagoonBuild.Spec.Project.Environment), + -1, + ), + "${project}", + shortName(lagoonBuild.Spec.Project.Name), -1, ), - "${project}", - shortName(lagoonBuild.Spec.Project.Name), - -1, ), - ), - }) + }) + } } if lagoonBuild.Spec.Build.CI != "" { podEnvs = append(podEnvs, corev1.EnvVar{ diff --git a/main.go b/main.go index 5be870b5..86e9a07e 100644 --- a/main.go +++ b/main.go @@ -132,6 +132,8 @@ func main() { var qosMaxBuilds int var qosDefaultValue int + var lffRouterURL bool + flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.") flag.StringVar(&lagoonTargetName, "lagoon-target-name", "ci-local-control-k8s", @@ -226,6 +228,12 @@ func main() { flag.IntVar(&nativeCronPodMinFrequency, "native-cron-pod-min-frequency", 15, "The number of lagoontask resources to keep per namespace.") + // this is enabled by default for now + // eventually will be disabled by default because support for the generation/modification of this will + // be handled by lagoon or the builds themselves + flag.BoolVar(&lffRouterURL, "lagoon-feature-flag-enable-router-url", true, + "Tells the controller to handle router-url generation or not") + // harbor configurations flag.BoolVar(&lffHarborEnabled, "enable-harbor", false, "Flag to enable this controller to talk to a specific harbor.") flag.StringVar(&harborURL, "harbor-url", "harbor.172.17.0.1.nip.io:32080", @@ -607,6 +615,7 @@ func main() { LFFForceIsolationNetworkPolicy: lffForceIsolationNetworkPolicy, LFFDefaultIsolationNetworkPolicy: lffDefaultIsolationNetworkPolicy, LFFBackupWeeklyRandom: lffBackupWeeklyRandom, + LFFRouterURL: lffRouterURL, LFFHarborEnabled: lffHarborEnabled, Harbor: harborConfig, LFFQoSEnabled: lffQoSEnabled, From bd96454e1be692ed717347ebb3fc34b6b2cb11b8 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 28 Oct 2021 12:25:40 +1100 Subject: [PATCH 28/35] fix: change the flag for backup-weekly feature to match others --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index 86e9a07e..fcc15fd9 100644 --- a/main.go +++ b/main.go @@ -223,7 +223,7 @@ func main() { "The cron definition for how often to run the lagoontask resources cleanup.") flag.IntVar(&tasksToKeep, "num-tasks-to-keep", 5, "The number of lagoontask resources to keep per namespace.") flag.IntVar(&taskPodsToKeep, "num-task-pods-to-keep", 1, "The number of task pods to keep per namespace.") - flag.BoolVar(&lffBackupWeeklyRandom, "lffBackupWeeklyRandom", false, + flag.BoolVar(&lffBackupWeeklyRandom, "lagoon-feature-flag-backup-weekly-random", false, "Tells Lagoon whether or not to use the \"weekly-random\" schedule for k8up backups.") flag.IntVar(&nativeCronPodMinFrequency, "native-cron-pod-min-frequency", 15, "The number of lagoontask resources to keep per namespace.") From aded3ffb2b6f17973e954d9b39c5fe561e26ad10 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 28 Oct 2021 16:52:05 +1100 Subject: [PATCH 29/35] chore: remove chart, this exists outside of this repository now --- charts/index.yaml | 104 --- charts/lagoon-builddeploy-0.1.0.tgz | Bin 4335 -> 0 bytes charts/lagoon-builddeploy-0.1.1.tgz | Bin 5129 -> 0 bytes charts/lagoon-builddeploy-0.1.2.tgz | Bin 5129 -> 0 bytes charts/lagoon-builddeploy-0.1.3.tgz | Bin 5140 -> 0 bytes charts/lagoon-builddeploy-0.1.4.tgz | Bin 5224 -> 0 bytes charts/lagoon-builddeploy-0.1.5.tgz | Bin 5236 -> 0 bytes charts/lagoon-builddeploy-0.1.6.tgz | Bin 5351 -> 0 bytes charts/lagoon-builddeploy-0.1.7.tgz | Bin 5352 -> 0 bytes charts/lagoon-builddeploy-0.1.8.tgz | Bin 5455 -> 0 bytes charts/lagoon-builddeploy-0.1.9.tgz | Bin 5969 -> 0 bytes charts/lagoon-builddeploy/.helmignore | 23 - charts/lagoon-builddeploy/Chart.yaml | 22 - .../lagoon-builddeploy/templates/_helpers.tpl | 59 -- .../templates/clusterrole.yaml | 29 - .../templates/clusterrolebinding.yaml | 25 - charts/lagoon-builddeploy/templates/crd.yaml | 856 ------------------ .../templates/deployment.yaml | 91 -- charts/lagoon-builddeploy/templates/role.yaml | 32 - .../templates/rolebinding.yaml | 13 - .../lagoon-builddeploy/templates/service.yaml | 16 - .../templates/serviceaccount.yaml | 7 - charts/lagoon-builddeploy/values.yaml | 80 -- 23 files changed, 1357 deletions(-) delete mode 100644 charts/index.yaml delete mode 100644 charts/lagoon-builddeploy-0.1.0.tgz delete mode 100644 charts/lagoon-builddeploy-0.1.1.tgz delete mode 100644 charts/lagoon-builddeploy-0.1.2.tgz delete mode 100644 charts/lagoon-builddeploy-0.1.3.tgz delete mode 100644 charts/lagoon-builddeploy-0.1.4.tgz delete mode 100644 charts/lagoon-builddeploy-0.1.5.tgz delete mode 100644 charts/lagoon-builddeploy-0.1.6.tgz delete mode 100644 charts/lagoon-builddeploy-0.1.7.tgz delete mode 100644 charts/lagoon-builddeploy-0.1.8.tgz delete mode 100644 charts/lagoon-builddeploy-0.1.9.tgz delete mode 100644 charts/lagoon-builddeploy/.helmignore delete mode 100644 charts/lagoon-builddeploy/Chart.yaml delete mode 100644 charts/lagoon-builddeploy/templates/_helpers.tpl delete mode 100644 charts/lagoon-builddeploy/templates/clusterrole.yaml delete mode 100644 charts/lagoon-builddeploy/templates/clusterrolebinding.yaml delete mode 100644 charts/lagoon-builddeploy/templates/crd.yaml delete mode 100644 charts/lagoon-builddeploy/templates/deployment.yaml delete mode 100644 charts/lagoon-builddeploy/templates/role.yaml delete mode 100644 charts/lagoon-builddeploy/templates/rolebinding.yaml delete mode 100644 charts/lagoon-builddeploy/templates/service.yaml delete mode 100644 charts/lagoon-builddeploy/templates/serviceaccount.yaml delete mode 100644 charts/lagoon-builddeploy/values.yaml diff --git a/charts/index.yaml b/charts/index.yaml deleted file mode 100644 index f98564c6..00000000 --- a/charts/index.yaml +++ /dev/null @@ -1,104 +0,0 @@ -apiVersion: v1 -entries: - lagoon-builddeploy: - - apiVersion: v2 - appVersion: 0.1.5 - created: "2020-12-22T14:16:05.104562+11:00" - description: A Helm chart for lagoon-builddeploy - digest: 5aea233c93bd9ba2f827f8fa59d50086edbf0794d6c76854b36eb063f77dd3b3 - name: lagoon-builddeploy - type: application - urls: - - lagoon-builddeploy-0.1.9.tgz - version: 0.1.9 - - apiVersion: v2 - appVersion: 0.1.5 - created: "2020-12-22T14:16:05.103946+11:00" - description: A Helm chart for lagoon-builddeploy - digest: 0033c3373d792df52213d2829280894df7f7570630e3dd774b478e753659d7e6 - name: lagoon-builddeploy - type: application - urls: - - lagoon-builddeploy-0.1.8.tgz - version: 0.1.8 - - apiVersion: v2 - appVersion: 0.1.4 - created: "2020-12-22T14:16:05.103375+11:00" - description: A Helm chart for lagoon-builddeploy - digest: 99be1a9a9f264170f52b4ce3df14bf95b8e54fd7e9b08d71b2f83b123700d63f - name: lagoon-builddeploy - type: application - urls: - - lagoon-builddeploy-0.1.7.tgz - version: 0.1.7 - - apiVersion: v2 - appVersion: 0.1.4 - created: "2020-12-22T14:16:05.102803+11:00" - description: A Helm chart for lagoon-builddeploy - digest: 0a0f4a4625c0f78a94b7c90a5ee9e2b5cd23d79781b55df8d9286a51cce7996c - name: lagoon-builddeploy - type: application - urls: - - lagoon-builddeploy-0.1.6.tgz - version: 0.1.6 - - apiVersion: v2 - appVersion: 0.1.4 - created: "2020-12-22T14:16:05.101316+11:00" - description: A Helm chart for lagoon-builddeploy - digest: 2398c2988750eeb3d0019f53de8efdc79b76512f84204ce36488cd10e836ed54 - name: lagoon-builddeploy - type: application - urls: - - lagoon-builddeploy-0.1.5.tgz - version: 0.1.5 - - apiVersion: v2 - appVersion: 0.1.4 - created: "2020-12-22T14:16:05.100594+11:00" - description: A Helm chart for lagoon-builddeploy - digest: 54e10fb69334bb73fadfd3dc603cf17efd110e3d53a37e19684c5a57dbd4ca59 - name: lagoon-builddeploy - type: application - urls: - - lagoon-builddeploy-0.1.4.tgz - version: 0.1.4 - - apiVersion: v2 - appVersion: 0.1.3 - created: "2020-12-22T14:16:05.099969+11:00" - description: A Helm chart for lagoon-builddeploy - digest: 7c97f2815d38e0a2f6d1041670eec750dcb88484105b9b231746a6649915ab0f - name: lagoon-builddeploy - type: application - urls: - - lagoon-builddeploy-0.1.3.tgz - version: 0.1.3 - - apiVersion: v2 - appVersion: 0.1.2 - created: "2020-12-22T14:16:05.099373+11:00" - description: A Helm chart for lagoon-builddeploy - digest: 7616e507ebdac9a8fa081b1925428dff700cee46e3d0948ee5f343864bf73873 - name: lagoon-builddeploy - type: application - urls: - - lagoon-builddeploy-0.1.2.tgz - version: 0.1.2 - - apiVersion: v2 - appVersion: 0.1.1 - created: "2020-12-22T14:16:05.098844+11:00" - description: A Helm chart for lagoon-builddeploy - digest: 1fa0435d49d0dd2762029cf140d5c6e233f00253bcdf60ca9a113d7dac3a73fd - name: lagoon-builddeploy - type: application - urls: - - lagoon-builddeploy-0.1.1.tgz - version: 0.1.1 - - apiVersion: v2 - appVersion: 0.1.0 - created: "2020-12-22T14:16:05.09827+11:00" - description: A Helm chart for lagoon-builddeploy - digest: de42c5e64e32c18a5ad15e138afe1eadec4e742eeb42f77faaf3188a8d25d1e3 - name: lagoon-builddeploy - type: application - urls: - - lagoon-builddeploy-0.1.0.tgz - version: 0.1.0 -generated: "2020-12-22T14:16:05.097532+11:00" diff --git a/charts/lagoon-builddeploy-0.1.0.tgz b/charts/lagoon-builddeploy-0.1.0.tgz deleted file mode 100644 index 7dbf3f7acfccfde9274dc32f89de994fc2902d76..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4335 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 diff --git a/charts/lagoon-builddeploy-0.1.3.tgz b/charts/lagoon-builddeploy-0.1.3.tgz deleted file mode 100644 index df6ab5ee8fa7395f275e7a40dbaea17a3dfbed1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5140 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%0AO=hO!(D$4 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 diff --git a/charts/lagoon-builddeploy-0.1.5.tgz b/charts/lagoon-builddeploy-0.1.5.tgz deleted file mode 100644 index 367c2e588cf964552cd9af6ad872a29d71ac951a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5236 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 diff --git a/charts/lagoon-builddeploy-0.1.6.tgz b/charts/lagoon-builddeploy-0.1.6.tgz deleted file mode 100644 index 0aba42786cd83174362e033b9321ce079b645a33..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5351 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 F007V@N+|#U diff --git a/charts/lagoon-builddeploy-0.1.7.tgz b/charts/lagoon-builddeploy-0.1.7.tgz deleted file mode 100644 index c89f0cd15d2f49fa7e6b58f7a93605d4a2d7e244..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5352 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 GyZ`{J#$_%5 diff --git a/charts/lagoon-builddeploy-0.1.8.tgz b/charts/lagoon-builddeploy-0.1.8.tgz deleted file mode 100644 index fe2824cf6f51db3584f63bbe09b232786537f7d2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5455 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 F001Clq@4f& diff --git a/charts/lagoon-builddeploy-0.1.9.tgz b/charts/lagoon-builddeploy-0.1.9.tgz deleted file mode 100644 index 8c171804b70d6f4c8494f88fac41aab382ba9cdf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5969 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 diff --git a/charts/lagoon-builddeploy/.helmignore b/charts/lagoon-builddeploy/.helmignore deleted file mode 100644 index 5d9272cd..00000000 --- a/charts/lagoon-builddeploy/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -# Common VCS dirs -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -# Common backup files -*.swp -*.bak -*.tmp -*~ -# Various IDEs -.project -.idea/ -*.tmproj -.vscode/ - diff --git a/charts/lagoon-builddeploy/Chart.yaml b/charts/lagoon-builddeploy/Chart.yaml deleted file mode 100644 index 31ce0d91..00000000 --- a/charts/lagoon-builddeploy/Chart.yaml +++ /dev/null @@ -1,22 +0,0 @@ -apiVersion: v2 -name: lagoon-builddeploy -description: A Helm chart for lagoon-builddeploy - -# A chart can be either an 'application' or a 'library' chart. -# -# Application charts are a collection of templates that can be packaged into versioned archives -# to be deployed. -# -# Library charts provide useful utilities or functions for the chart developer. They're included as -# a dependency of application charts to inject those utilities and functions into the rendering -# pipeline. Library charts do not define any templates and therefore cannot be deployed. -type: application - -# This is the chart version. This version number should be incremented each time you make changes -# to the chart and its templates, including the app version. -version: 0.1.9 - -# This is the version number of the application being deployed. This version number should be -# incremented each time you make changes to the application. -appVersion: 0.1.5 - diff --git a/charts/lagoon-builddeploy/templates/_helpers.tpl b/charts/lagoon-builddeploy/templates/_helpers.tpl deleted file mode 100644 index db40e1a6..00000000 --- a/charts/lagoon-builddeploy/templates/_helpers.tpl +++ /dev/null @@ -1,59 +0,0 @@ -{{/* vim: set filetype=mustache: */}} -{{/* -Expand the name of the chart. -*/}} -{{- define "lagoon-builddeploy.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "lagoon-builddeploy.fullname" -}} -{{- if .Values.fullnameOverride -}} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- $name := default .Chart.Name .Values.nameOverride -}} -{{- if contains $name .Release.Name -}} -{{- .Release.Name | trunc 63 | trimSuffix "-" -}} -{{- else -}} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} -{{- end -}} -{{- end -}} -{{- end -}} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "lagoon-builddeploy.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} -{{- end -}} - -{{/* -Common labels -*/}} -{{- define "lagoon-builddeploy.labels" -}} -helm.sh/chart: {{ include "lagoon-builddeploy.chart" . }} -{{ include "lagoon-builddeploy.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end -}} - -{{/* -Selector labels -*/}} -{{- define "lagoon-builddeploy.selectorLabels" -}} -app.kubernetes.io/name: {{ include "lagoon-builddeploy.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end -}} - -{{/* -Create the name of the service account to use -*/}} -{{- define "lagoon-builddeploy.serviceAccountName" -}} -{{ default "lagoon-builddeploy" .Values.serviceAccount.nameOverride }} -{{- end -}} diff --git a/charts/lagoon-builddeploy/templates/clusterrole.yaml b/charts/lagoon-builddeploy/templates/clusterrole.yaml deleted file mode 100644 index af86f54b..00000000 --- a/charts/lagoon-builddeploy/templates/clusterrole.yaml +++ /dev/null @@ -1,29 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: {{ include "lagoon-builddeploy.fullname" . }}-manager -rules: -- apiGroups: - - '*' - resources: - - '*' - verbs: - - '*' ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: {{ include "lagoon-builddeploy.fullname" . }}-proxy -rules: -- apiGroups: - - authentication.k8s.io - resources: - - tokenreviews - verbs: - - create -- apiGroups: - - authorization.k8s.io - resources: - - subjectaccessreviews - verbs: - - create \ No newline at end of file diff --git a/charts/lagoon-builddeploy/templates/clusterrolebinding.yaml b/charts/lagoon-builddeploy/templates/clusterrolebinding.yaml deleted file mode 100644 index 68a7ef55..00000000 --- a/charts/lagoon-builddeploy/templates/clusterrolebinding.yaml +++ /dev/null @@ -1,25 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: {{ include "lagoon-builddeploy.fullname" . }}-manager -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ include "lagoon-builddeploy.fullname" . }}-manager -subjects: -- kind: ServiceAccount - name: {{ include "lagoon-builddeploy.serviceAccountName" . }} - namespace: {{ .Release.Namespace | quote }} ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: {{ include "lagoon-builddeploy.fullname" . }}-proxy -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: {{ include "lagoon-builddeploy.fullname" . }}-proxy -subjects: -- kind: ServiceAccount - name: {{ include "lagoon-builddeploy.serviceAccountName" . }} - namespace: {{ .Release.Namespace | quote }} \ No newline at end of file diff --git a/charts/lagoon-builddeploy/templates/crd.yaml b/charts/lagoon-builddeploy/templates/crd.yaml deleted file mode 100644 index 14e376d1..00000000 --- a/charts/lagoon-builddeploy/templates/crd.yaml +++ /dev/null @@ -1,856 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.2.4 - creationTimestamp: null - name: lagoonbuilds.lagoon.amazee.io -spec: - group: lagoon.amazee.io - names: - kind: LagoonBuild - listKind: LagoonBuildList - plural: lagoonbuilds - singular: lagoonbuild - scope: Namespaced - validation: - openAPIV3Schema: - description: LagoonBuild is the Schema for the lagoonbuilds API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: LagoonBuildSpec defines the desired state of LagoonBuild - properties: - branch: - description: Branch contains the branch name used for a branch deployment. - properties: - name: - type: string - type: object - build: - description: Build contains the type of build, and the image to use - for the builder. - properties: - ci: - type: string - image: - type: string - type: - type: string - required: - - type - type: object - gitReference: - type: string - project: - description: Project contains the project information from lagoon. - properties: - deployTarget: - type: string - environment: - type: string - environmentType: - type: string - gitUrl: - type: string - key: - format: byte - type: string - monitoring: - description: Monitoring contains the monitoring information for - the project in Lagoon. - properties: - contact: - type: string - statuspageID: - type: string - type: object - name: - type: string - namespacePattern: - type: string - productionEnvironment: - type: string - projectSecret: - type: string - registry: - type: string - routerPattern: - type: string - standbyEnvironment: - type: string - subfolder: - type: string - uiLink: - type: string - variables: - description: Variables contains the project and environment variables - from lagoon. - properties: - environment: - format: byte - type: string - project: - format: byte - type: string - type: object - required: - - deployTarget - - environment - - environmentType - - gitUrl - - key - - monitoring - - name - - productionEnvironment - - projectSecret - - standbyEnvironment - - variables - type: object - promote: - description: Promote contains the information for a promote deployment. - properties: - sourceEnvironment: - type: string - sourceProject: - type: string - type: object - pullrequest: - description: Pullrequest contains the information for a pullrequest - deployment. - properties: - baseBranch: - type: string - baseSha: - type: string - headBranch: - type: string - headSha: - type: string - number: - type: string - title: - type: string - type: object - required: - - build - - gitReference - - project - type: object - status: - description: LagoonBuildStatus defines the observed state of LagoonBuild - properties: - conditions: - description: 'INSERT ADDITIONAL STATUS FIELD - define observed state - of cluster Important: Run "make" to regenerate code after modifying - this file' - items: - description: LagoonConditions defines the observed conditions of the - pods. - properties: - lastTransitionTime: - type: string - status: - type: string - type: - description: JobConditionType const for the status type - type: string - required: - - lastTransitionTime - - status - - type - type: object - type: array - log: - format: byte - type: string - type: object - statusMessages: - description: LagoonStatusMessages is where unsent messages are stored for - re-sending. - properties: - buildLogMessage: - description: LagoonLog is used to sendToLagoonLogs messaging queue this - is general logging information - properties: - event: - type: string - message: - type: string - meta: - description: LagoonLogMeta is the metadata that is used by logging - in Lagoon. - properties: - advancedData: - type: string - branchName: - type: string - buildName: - type: string - buildPhase: - type: string - endTime: - type: string - environment: - type: string - jobName: - type: string - jobStatus: - type: string - key: - type: string - logLink: - type: string - monitoringUrls: - items: - type: string - type: array - project: - type: string - projectName: - type: string - remoteId: - type: string - route: - type: string - routes: - items: - type: string - type: array - services: - items: - type: string - type: array - startTime: - type: string - task: - description: LagoonTaskInfo defines what a task can use to communicate - with Lagoon via SSH/API. - properties: - apiHost: - type: string - command: - type: string - id: - type: string - name: - type: string - service: - type: string - sshHost: - type: string - sshPort: - type: string - required: - - id - type: object - type: object - project: - type: string - severity: - type: string - uuid: - type: string - type: object - environmentMessage: - description: LagoonMessage is used for sending build info back to Lagoon - messaging queue to update the environment or deployment - properties: - meta: - description: LagoonLogMeta is the metadata that is used by logging - in Lagoon. - properties: - advancedData: - type: string - branchName: - type: string - buildName: - type: string - buildPhase: - type: string - endTime: - type: string - environment: - type: string - jobName: - type: string - jobStatus: - type: string - key: - type: string - logLink: - type: string - monitoringUrls: - items: - type: string - type: array - project: - type: string - projectName: - type: string - remoteId: - type: string - route: - type: string - routes: - items: - type: string - type: array - services: - items: - type: string - type: array - startTime: - type: string - task: - description: LagoonTaskInfo defines what a task can use to communicate - with Lagoon via SSH/API. - properties: - apiHost: - type: string - command: - type: string - id: - type: string - name: - type: string - service: - type: string - sshHost: - type: string - sshPort: - type: string - required: - - id - type: object - type: object - namespace: - type: string - type: - type: string - type: object - statusMessage: - description: LagoonLog is used to sendToLagoonLogs messaging queue this - is general logging information - properties: - event: - type: string - message: - type: string - meta: - description: LagoonLogMeta is the metadata that is used by logging - in Lagoon. - properties: - advancedData: - type: string - branchName: - type: string - buildName: - type: string - buildPhase: - type: string - endTime: - type: string - environment: - type: string - jobName: - type: string - jobStatus: - type: string - key: - type: string - logLink: - type: string - monitoringUrls: - items: - type: string - type: array - project: - type: string - projectName: - type: string - remoteId: - type: string - route: - type: string - routes: - items: - type: string - type: array - services: - items: - type: string - type: array - startTime: - type: string - task: - description: LagoonTaskInfo defines what a task can use to communicate - with Lagoon via SSH/API. - properties: - apiHost: - type: string - command: - type: string - id: - type: string - name: - type: string - service: - type: string - sshHost: - type: string - sshPort: - type: string - required: - - id - type: object - type: object - project: - type: string - severity: - type: string - uuid: - type: string - type: object - type: object - type: object - version: v1alpha1 - versions: - - name: v1alpha1 - served: true - storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] ---- -apiVersion: apiextensions.k8s.io/v1beta1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.2.4 - creationTimestamp: null - name: lagoontasks.lagoon.amazee.io -spec: - group: lagoon.amazee.io - names: - kind: LagoonTask - listKind: LagoonTaskList - plural: lagoontasks - singular: lagoontask - scope: Namespaced - validation: - openAPIV3Schema: - description: LagoonTask is the Schema for the lagoontasks API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: LagoonTaskSpec defines the desired state of LagoonTask - properties: - advancedTask: - description: LagoonAdvancedTaskInfo defines what an advanced task can - use for the creation of the pod. - properties: - JSONPayload: - type: string - runnerImage: - type: string - type: object - environment: - description: LagoonTaskEnvironment defines the lagoon environment information. - properties: - environmentType: - type: string - id: - type: string - name: - type: string - openshiftProjectName: - type: string - project: - type: string - required: - - environmentType - - id - - name - - openshiftProjectName - - project - type: object - key: - description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - Important: Run "make" to regenerate code after modifying this file' - type: string - misc: - description: LagoonMiscInfo defines the resource or backup information - for a misc task. - properties: - backup: - description: LagoonMiscBackupInfo defines the information for a - backup. - properties: - backupId: - type: string - id: - type: string - source: - type: string - required: - - backupId - - id - - source - type: object - id: - type: string - miscResource: - format: byte - type: string - name: - type: string - required: - - id - type: object - project: - description: LagoonTaskProject defines the lagoon project information. - properties: - id: - type: string - name: - type: string - required: - - id - - name - type: object - task: - description: LagoonTaskInfo defines what a task can use to communicate - with Lagoon via SSH/API. - properties: - apiHost: - type: string - command: - type: string - id: - type: string - name: - type: string - service: - type: string - sshHost: - type: string - sshPort: - type: string - required: - - id - type: object - type: object - status: - description: LagoonTaskStatus defines the observed state of LagoonTask - properties: - conditions: - description: 'INSERT ADDITIONAL STATUS FIELD - define observed state - of cluster Important: Run "make" to regenerate code after modifying - this file' - items: - description: LagoonConditions defines the observed conditions of the - pods. - properties: - lastTransitionTime: - type: string - status: - type: string - type: - description: JobConditionType const for the status type - type: string - required: - - lastTransitionTime - - status - - type - type: object - type: array - log: - format: byte - type: string - type: object - statusMessages: - description: LagoonStatusMessages is where unsent messages are stored for - re-sending. - properties: - buildLogMessage: - description: LagoonLog is used to sendToLagoonLogs messaging queue this - is general logging information - properties: - event: - type: string - message: - type: string - meta: - description: LagoonLogMeta is the metadata that is used by logging - in Lagoon. - properties: - advancedData: - type: string - branchName: - type: string - buildName: - type: string - buildPhase: - type: string - endTime: - type: string - environment: - type: string - jobName: - type: string - jobStatus: - type: string - key: - type: string - logLink: - type: string - monitoringUrls: - items: - type: string - type: array - project: - type: string - projectName: - type: string - remoteId: - type: string - route: - type: string - routes: - items: - type: string - type: array - services: - items: - type: string - type: array - startTime: - type: string - task: - description: LagoonTaskInfo defines what a task can use to communicate - with Lagoon via SSH/API. - properties: - apiHost: - type: string - command: - type: string - id: - type: string - name: - type: string - service: - type: string - sshHost: - type: string - sshPort: - type: string - required: - - id - type: object - type: object - project: - type: string - severity: - type: string - uuid: - type: string - type: object - environmentMessage: - description: LagoonMessage is used for sending build info back to Lagoon - messaging queue to update the environment or deployment - properties: - meta: - description: LagoonLogMeta is the metadata that is used by logging - in Lagoon. - properties: - advancedData: - type: string - branchName: - type: string - buildName: - type: string - buildPhase: - type: string - endTime: - type: string - environment: - type: string - jobName: - type: string - jobStatus: - type: string - key: - type: string - logLink: - type: string - monitoringUrls: - items: - type: string - type: array - project: - type: string - projectName: - type: string - remoteId: - type: string - route: - type: string - routes: - items: - type: string - type: array - services: - items: - type: string - type: array - startTime: - type: string - task: - description: LagoonTaskInfo defines what a task can use to communicate - with Lagoon via SSH/API. - properties: - apiHost: - type: string - command: - type: string - id: - type: string - name: - type: string - service: - type: string - sshHost: - type: string - sshPort: - type: string - required: - - id - type: object - type: object - namespace: - type: string - type: - type: string - type: object - statusMessage: - description: LagoonLog is used to sendToLagoonLogs messaging queue this - is general logging information - properties: - event: - type: string - message: - type: string - meta: - description: LagoonLogMeta is the metadata that is used by logging - in Lagoon. - properties: - advancedData: - type: string - branchName: - type: string - buildName: - type: string - buildPhase: - type: string - endTime: - type: string - environment: - type: string - jobName: - type: string - jobStatus: - type: string - key: - type: string - logLink: - type: string - monitoringUrls: - items: - type: string - type: array - project: - type: string - projectName: - type: string - remoteId: - type: string - route: - type: string - routes: - items: - type: string - type: array - services: - items: - type: string - type: array - startTime: - type: string - task: - description: LagoonTaskInfo defines what a task can use to communicate - with Lagoon via SSH/API. - properties: - apiHost: - type: string - command: - type: string - id: - type: string - name: - type: string - service: - type: string - sshHost: - type: string - sshPort: - type: string - required: - - id - type: object - type: object - project: - type: string - severity: - type: string - uuid: - type: string - type: object - type: object - type: object - version: v1alpha1 - versions: - - name: v1alpha1 - served: true - storage: true -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/charts/lagoon-builddeploy/templates/deployment.yaml b/charts/lagoon-builddeploy/templates/deployment.yaml deleted file mode 100644 index 5cc1ad23..00000000 --- a/charts/lagoon-builddeploy/templates/deployment.yaml +++ /dev/null @@ -1,91 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "lagoon-builddeploy.fullname" . }} - labels: - {{- include "lagoon-builddeploy.labels" . | nindent 4 }} -spec: - replicas: {{ .Values.replicaCount }} - selector: - matchLabels: - {{- include "lagoon-builddeploy.selectorLabels" . | nindent 6 }} - template: - metadata: - labels: - {{- include "lagoon-builddeploy.selectorLabels" . | nindent 8 }} - spec: - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - serviceAccountName: {{ include "lagoon-builddeploy.serviceAccountName" . }} - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - containers: - - args: - - --secure-listen-address=0.0.0.0:8443 - - --upstream=http://127.0.0.1:8080/ - - --logtostderr=true - - --v=10 - image: "{{ .Values.kubeRbacProxy.image.repository }}:{{ .Values.kubeRbacProxy.image.tag }}" - name: kube-rbac-proxy - ports: - - containerPort: 8443 - name: https - - args: - {{- range $key, $value := .Values.extraArgs }} - {{- if $value }} - - --{{ $key }}={{ $value }} - {{- else }} - - --{{ $key }} - {{- end }} - {{- end }} - {{- if .Values.vars.isOpenshift }} - - --is-openshift - {{- end }} - {{- if .Values.vars.randomPrefix }} - - --random-prefix - {{- end }} - command: - - /manager - image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" - imagePullPolicy: Always - env: - - name: RABBITMQ_USERNAME - value: '{{ .Values.vars.rabbitUsername }}' - - name: RABBITMQ_PASSWORD - value: '{{ .Values.vars.rabbitPassword }}' - - name: RABBITMQ_HOSTNAME - value: '{{ .Values.vars.rabbitHostname }}' - - name: LAGOON_TARGET_NAME - value: '{{ .Values.vars.lagoonTargetName }}' - - name: PENDING_MESSAGE_CRON - value: '{{ .Values.vars.pendingMessageCron }}' - - name: OVERRIDE_BUILD_DEPLOY_DIND_IMAGE - value: '{{ .Values.vars.overrideBuildDeployImage }}' - - name: NAMESPACE_PREFIX - value: '{{ .Values.vars.namespacePrefix }}' - - name: CONTROLLER_NAMESPACE - valueFrom: - fieldRef: - fieldPath: metadata.namespace - name: manager - resources: - limits: - cpu: 100m - memory: 30Mi - requests: - cpu: 100m - memory: 20Mi - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} diff --git a/charts/lagoon-builddeploy/templates/role.yaml b/charts/lagoon-builddeploy/templates/role.yaml deleted file mode 100644 index 3d6db570..00000000 --- a/charts/lagoon-builddeploy/templates/role.yaml +++ /dev/null @@ -1,32 +0,0 @@ ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: {{ include "lagoon-builddeploy.fullname" . }}-leader-election -rules: -- apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch - - create - - update - - patch - - delete -- apiGroups: - - "" - resources: - - configmaps/status - verbs: - - get - - update - - patch -- apiGroups: - - "" - resources: - - events - verbs: - - create \ No newline at end of file diff --git a/charts/lagoon-builddeploy/templates/rolebinding.yaml b/charts/lagoon-builddeploy/templates/rolebinding.yaml deleted file mode 100644 index fff44756..00000000 --- a/charts/lagoon-builddeploy/templates/rolebinding.yaml +++ /dev/null @@ -1,13 +0,0 @@ -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: {{ include "lagoon-builddeploy.fullname" . }}-leader-election - namespace: {{ .Release.Namespace | quote }} -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: {{ include "lagoon-builddeploy.fullname" . }}-leader-election -subjects: -- kind: ServiceAccount - name: {{ include "lagoon-builddeploy.serviceAccountName" . }} - namespace: {{ .Release.Namespace | quote }} \ No newline at end of file diff --git a/charts/lagoon-builddeploy/templates/service.yaml b/charts/lagoon-builddeploy/templates/service.yaml deleted file mode 100644 index 5faf4b5c..00000000 --- a/charts/lagoon-builddeploy/templates/service.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -apiVersion: v1 -kind: Service -metadata: - name: {{ include "lagoon-builddeploy.fullname" . }} - labels: - {{- include "lagoon-builddeploy.labels" . | nindent 4 }} -spec: - type: {{ .Values.service.type }} - ports: - - port: {{ .Values.service.port }} - targetPort: https - protocol: TCP - name: https - selector: - {{- include "lagoon-builddeploy.selectorLabels" . | nindent 4 }} diff --git a/charts/lagoon-builddeploy/templates/serviceaccount.yaml b/charts/lagoon-builddeploy/templates/serviceaccount.yaml deleted file mode 100644 index ab02f7bf..00000000 --- a/charts/lagoon-builddeploy/templates/serviceaccount.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "lagoon-builddeploy.serviceAccountName" . }} - labels: -{{ include "lagoon-builddeploy.labels" . | nindent 4 }} - diff --git a/charts/lagoon-builddeploy/values.yaml b/charts/lagoon-builddeploy/values.yaml deleted file mode 100644 index a2dbab8d..00000000 --- a/charts/lagoon-builddeploy/values.yaml +++ /dev/null @@ -1,80 +0,0 @@ -# Default values for lagoon-builddeploy. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -replicaCount: 1 - -image: - repository: amazeeio/lagoon-builddeploy - tag: v0.1.5 - pullPolicy: IfNotPresent - -kubeRbacProxy: - image: - repository: gcr.io/kubebuilder/kube-rbac-proxy - tag: v0.4.1 - -imagePullSecrets: [] -nameOverride: "" -fullnameOverride: "" - -extraArgs: - metrics-addr: 127.0.0.1:8080 - enable-leader-election: true -# If set, all namespaces will be generated with a specific prefix defined here. -# namespace-prefix: cluster-environment-or-name -# If set, all namespaces will be generated with a specific random prefix, if namespace-prefix is defined, -# it is ingored in favor of the random prefix. -# random-prefix: true - - -# namespacePrefix is limited to 8 characters, and will be automatically truncated -vars: - rabbitUsername: '' - rabbitPassword: '' - rabbitHostname: '' - lagoonTargetName: '' - pendingMessageCron: '*/5 * * * *' - overrideBuildDeployImage: '' - namespacePrefix: '' - randomPrefix: false - isOpenshift: false - -serviceAccount: - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - nameOverride: - -podSecurityContext: {} - # fsGroup: 2000 - -securityContext: {} - # capabilities: - # drop: - # - ALL - # readOnlyRootFilesystem: true - # runAsNonRoot: true - # runAsUser: 1000 - -service: - type: ClusterIP - port: 8443 - -resources: {} - # We usually recommend not to specify default resources and to leave this as a conscious - # choice for the user. This also increases chances charts run on environments with little - # resources, such as Minikube. If you do want to specify resources, uncomment the following - # lines, adjust them as necessary, and remove the curly braces after 'resources:'. - # limits: - # cpu: 100m - # memory: 128Mi - # requests: - # cpu: 100m - # memory: 128Mi - -nodeSelector: {} - -tolerations: [] - -affinity: {} - From 3ee8418a50357205e238eea2974b17b6f511e48f Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 28 Oct 2021 16:53:08 +1100 Subject: [PATCH 30/35] chore: update controller-gen to 0.6.2, bump go to 1.16, and use k8s 1.22 supported packages. fix broken code after big step up --- Dockerfile | 2 +- Makefile | 2 +- .../bases/lagoon.amazee.io_lagoonbuilds.yaml | 821 +++++++++-------- .../bases/lagoon.amazee.io_lagoontasks.yaml | 760 +++++++-------- .../patches/cainjection_in_lagoonbuilds.yaml | 2 +- .../patches/cainjection_in_lagoontasks.yaml | 2 +- .../crd/patches/webhook_in_lagoonbuilds.yaml | 19 +- .../crd/patches/webhook_in_lagoontasks.yaml | 19 +- config/default/webhookcainjection_patch.yaml | 4 +- controllers/controller_predicates.go | 44 +- controllers/lagoonbuild_controller.go | 7 +- controllers/lagoonbuild_deletionhandlers.go | 12 +- controllers/lagoonbuild_helpers.go | 6 +- controllers/lagoonbuild_qoshandler.go | 2 +- controllers/lagoonbuild_standardhandler.go | 2 +- controllers/lagoonmonitor_buildhandlers.go | 16 +- controllers/lagoonmonitor_controller.go | 9 +- controllers/lagoonmonitor_taskhandlers.go | 12 +- controllers/lagoontask_controller.go | 7 +- controllers/suite_test.go | 5 +- go.mod | 22 +- go.sum | 868 ++++++++++++++---- handlers/message_queue.go | 2 +- 23 files changed, 1570 insertions(+), 1075 deletions(-) diff --git a/Dockerfile b/Dockerfile index dd18bdd9..3f28ec62 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build the manager binary -FROM golang:1.13 as builder +FROM golang:1.16-alpine3.13 as builder WORKDIR /workspace # Copy the Go Modules manifests diff --git a/Makefile b/Makefile index 7eb998f6..a2045d56 100644 --- a/Makefile +++ b/Makefile @@ -73,7 +73,7 @@ ifeq (, $(shell which controller-gen)) CONTROLLER_GEN_TMP_DIR=$$(mktemp -d) ;\ cd $$CONTROLLER_GEN_TMP_DIR ;\ go mod init tmp ;\ - go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.2.4 ;\ + go get sigs.k8s.io/controller-tools/cmd/controller-gen@v0.6.2 ;\ rm -rf $$CONTROLLER_GEN_TMP_DIR ;\ } CONTROLLER_GEN=$(GOBIN)/controller-gen diff --git a/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml b/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml index 13e82e06..6da605e5 100644 --- a/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml +++ b/config/crd/bases/lagoon.amazee.io_lagoonbuilds.yaml @@ -1,10 +1,10 @@ --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.4 + controller-gen.kubebuilder.io/version: v0.6.2 creationTimestamp: null name: lagoonbuilds.lagoon.amazee.io spec: @@ -15,445 +15,444 @@ spec: plural: lagoonbuilds singular: lagoonbuild scope: Namespaced - validation: - openAPIV3Schema: - description: LagoonBuild is the Schema for the lagoonbuilds API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: LagoonBuildSpec defines the desired state of LagoonBuild - properties: - branch: - description: Branch contains the branch name used for a branch deployment. - properties: - name: - type: string - type: object - build: - description: Build contains the type of build, and the image to use - for the builder. - properties: - bulkId: - type: string - ci: - type: string - image: - type: string - priority: - type: integer - type: - type: string - required: - - type - type: object - gitReference: - type: string - project: - description: Project contains the project information from lagoon. - properties: - deployTarget: - type: string - environment: - type: string - environmentId: - type: integer - environmentIdling: - type: integer - environmentType: - type: string - gitUrl: - type: string - id: - type: integer - key: - format: byte - type: string - monitoring: - description: Monitoring contains the monitoring information for - the project in Lagoon. - properties: - contact: - type: string - statuspageID: - type: string - type: object - name: - type: string - namespacePattern: - type: string - productionEnvironment: - type: string - projectIdling: - type: integer - projectSecret: - type: string - registry: - type: string - routerPattern: - type: string - standbyEnvironment: - type: string - subfolder: - type: string - uiLink: - type: string - variables: - description: Variables contains the project and environment variables - from lagoon. - properties: - environment: - format: byte - type: string - project: - format: byte - type: string - type: object - required: - - deployTarget - - environment - - environmentType - - gitUrl - - key - - monitoring - - name - - productionEnvironment - - projectSecret - - standbyEnvironment - - variables - type: object - promote: - description: Promote contains the information for a promote deployment. - properties: - sourceEnvironment: - type: string - sourceProject: - type: string - type: object - pullrequest: - description: Pullrequest contains the information for a pullrequest - deployment. - properties: - baseBranch: - type: string - baseSha: - type: string - headBranch: - type: string - headSha: - type: string - number: - type: string - title: - type: string - type: object - required: - - build - - gitReference - - project - type: object - status: - description: LagoonBuildStatus defines the observed state of LagoonBuild - properties: - conditions: - description: 'INSERT ADDITIONAL STATUS FIELD - define observed state - of cluster Important: Run "make" to regenerate code after modifying - this file' - items: - description: LagoonBuildConditions defines the observed conditions - of build pods. + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: LagoonBuild is the Schema for the lagoonbuilds API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: LagoonBuildSpec defines the desired state of LagoonBuild + properties: + branch: + description: Branch contains the branch name used for a branch deployment. properties: - lastTransitionTime: + name: type: string - status: + type: object + build: + description: Build contains the type of build, and the image to use + for the builder. + properties: + bulkId: + type: string + ci: + type: string + image: type: string + priority: + type: integer type: - description: BuildStatusType const for the status type type: string required: - - lastTransitionTime - - status - type type: object - type: array - log: - format: byte - type: string - type: object - statusMessages: - description: LagoonStatusMessages is where unsent messages are stored for - re-sending. - properties: - buildLogMessage: - description: LagoonLog is used to sendToLagoonLogs messaging queue this - is general logging information - properties: - event: - type: string - message: - type: string - meta: - description: LagoonLogMeta is the metadata that is used by logging - in Lagoon. - properties: - advancedData: - type: string - branchName: - type: string - buildName: - type: string - buildPhase: - type: string - endTime: - type: string - environment: - type: string - environmentId: - type: integer - jobName: - type: string - jobStatus: - type: string - key: - type: string - logLink: - type: string - monitoringUrls: - items: + gitReference: + type: string + project: + description: Project contains the project information from lagoon. + properties: + deployTarget: + type: string + environment: + type: string + environmentId: + type: integer + environmentIdling: + type: integer + environmentType: + type: string + gitUrl: + type: string + id: + type: integer + key: + format: byte + type: string + monitoring: + description: Monitoring contains the monitoring information for + the project in Lagoon. + properties: + contact: type: string - type: array - project: - type: string - projectId: - type: integer - projectName: - type: string - remoteId: - type: string - route: - type: string - routes: - items: + statuspageID: + type: string + type: object + name: + type: string + namespacePattern: + type: string + productionEnvironment: + type: string + projectIdling: + type: integer + projectSecret: + type: string + registry: + type: string + routerPattern: + type: string + standbyEnvironment: + type: string + subfolder: + type: string + uiLink: + type: string + variables: + description: Variables contains the project and environment variables + from lagoon. + properties: + environment: + format: byte type: string - type: array - services: - items: + project: + format: byte type: string - type: array - startTime: - type: string - task: - description: LagoonTaskInfo defines what a task can use to communicate - with Lagoon via SSH/API. - properties: - apiHost: - type: string - command: - type: string - id: - type: string - name: - type: string - service: - type: string - sshHost: - type: string - sshPort: - type: string - required: - - id - type: object - type: object - project: - type: string - severity: - type: string - uuid: - type: string - type: object - environmentMessage: - description: LagoonMessage is used for sending build info back to Lagoon - messaging queue to update the environment or deployment - properties: - meta: - description: LagoonLogMeta is the metadata that is used by logging - in Lagoon. + type: object + required: + - deployTarget + - environment + - environmentType + - gitUrl + - key + - monitoring + - name + - productionEnvironment + - projectSecret + - standbyEnvironment + - variables + type: object + promote: + description: Promote contains the information for a promote deployment. + properties: + sourceEnvironment: + type: string + sourceProject: + type: string + type: object + pullrequest: + description: Pullrequest contains the information for a pullrequest + deployment. + properties: + baseBranch: + type: string + baseSha: + type: string + headBranch: + type: string + headSha: + type: string + number: + type: string + title: + type: string + type: object + required: + - build + - gitReference + - project + type: object + status: + description: LagoonBuildStatus defines the observed state of LagoonBuild + properties: + conditions: + description: 'INSERT ADDITIONAL STATUS FIELD - define observed state + of cluster Important: Run "make" to regenerate code after modifying + this file' + items: + description: LagoonBuildConditions defines the observed conditions + of build pods. properties: - advancedData: - type: string - branchName: - type: string - buildName: - type: string - buildPhase: - type: string - endTime: + lastTransitionTime: type: string - environment: + status: type: string - environmentId: - type: integer - jobName: + type: + description: BuildStatusType const for the status type type: string - jobStatus: - type: string - key: - type: string - logLink: - type: string - monitoringUrls: - items: + required: + - lastTransitionTime + - status + - type + type: object + type: array + log: + format: byte + type: string + type: object + statusMessages: + description: LagoonStatusMessages is where unsent messages are stored + for re-sending. + properties: + buildLogMessage: + description: LagoonLog is used to sendToLagoonLogs messaging queue + this is general logging information + properties: + event: + type: string + message: + type: string + meta: + description: LagoonLogMeta is the metadata that is used by logging + in Lagoon. + properties: + advancedData: type: string - type: array - project: - type: string - projectId: - type: integer - projectName: - type: string - remoteId: - type: string - route: - type: string - routes: - items: + branchName: type: string - type: array - services: - items: + buildName: type: string - type: array - startTime: - type: string - task: - description: LagoonTaskInfo defines what a task can use to communicate - with Lagoon via SSH/API. - properties: - apiHost: - type: string - command: - type: string - id: - type: string - name: - type: string - service: + buildPhase: + type: string + endTime: + type: string + environment: + type: string + environmentId: + type: integer + jobName: + type: string + jobStatus: + type: string + key: + type: string + logLink: + type: string + monitoringUrls: + items: type: string - sshHost: + type: array + project: + type: string + projectId: + type: integer + projectName: + type: string + remoteId: + type: string + route: + type: string + routes: + items: type: string - sshPort: + type: array + services: + items: type: string - required: - - id - type: object - type: object - namespace: - type: string - type: - type: string - type: object - statusMessage: - description: LagoonLog is used to sendToLagoonLogs messaging queue this - is general logging information - properties: - event: - type: string - message: - type: string - meta: - description: LagoonLogMeta is the metadata that is used by logging - in Lagoon. - properties: - advancedData: - type: string - branchName: - type: string - buildName: - type: string - buildPhase: - type: string - endTime: - type: string - environment: - type: string - environmentId: - type: integer - jobName: - type: string - jobStatus: - type: string - key: - type: string - logLink: - type: string - monitoringUrls: - items: + type: array + startTime: type: string - type: array - project: - type: string - projectId: - type: integer - projectName: - type: string - remoteId: - type: string - route: - type: string - routes: - items: + task: + description: LagoonTaskInfo defines what a task can use to + communicate with Lagoon via SSH/API. + properties: + apiHost: + type: string + command: + type: string + id: + type: string + name: + type: string + service: + type: string + sshHost: + type: string + sshPort: + type: string + required: + - id + type: object + type: object + project: + type: string + severity: + type: string + uuid: + type: string + type: object + environmentMessage: + description: LagoonMessage is used for sending build info back to + Lagoon messaging queue to update the environment or deployment + properties: + meta: + description: LagoonLogMeta is the metadata that is used by logging + in Lagoon. + properties: + advancedData: type: string - type: array - services: - items: + branchName: type: string - type: array - startTime: - type: string - task: - description: LagoonTaskInfo defines what a task can use to communicate - with Lagoon via SSH/API. - properties: - apiHost: - type: string - command: + buildName: + type: string + buildPhase: + type: string + endTime: + type: string + environment: + type: string + environmentId: + type: integer + jobName: + type: string + jobStatus: + type: string + key: + type: string + logLink: + type: string + monitoringUrls: + items: type: string - id: + type: array + project: + type: string + projectId: + type: integer + projectName: + type: string + remoteId: + type: string + route: + type: string + routes: + items: type: string - name: + type: array + services: + items: type: string - service: + type: array + startTime: + type: string + task: + description: LagoonTaskInfo defines what a task can use to + communicate with Lagoon via SSH/API. + properties: + apiHost: + type: string + command: + type: string + id: + type: string + name: + type: string + service: + type: string + sshHost: + type: string + sshPort: + type: string + required: + - id + type: object + type: object + namespace: + type: string + type: + type: string + type: object + statusMessage: + description: LagoonLog is used to sendToLagoonLogs messaging queue + this is general logging information + properties: + event: + type: string + message: + type: string + meta: + description: LagoonLogMeta is the metadata that is used by logging + in Lagoon. + properties: + advancedData: + type: string + branchName: + type: string + buildName: + type: string + buildPhase: + type: string + endTime: + type: string + environment: + type: string + environmentId: + type: integer + jobName: + type: string + jobStatus: + type: string + key: + type: string + logLink: + type: string + monitoringUrls: + items: type: string - sshHost: + type: array + project: + type: string + projectId: + type: integer + projectName: + type: string + remoteId: + type: string + route: + type: string + routes: + items: type: string - sshPort: + type: array + services: + items: type: string - required: - - id - type: object - type: object - project: - type: string - severity: - type: string - uuid: - type: string - type: object - type: object - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: array + startTime: + type: string + task: + description: LagoonTaskInfo defines what a task can use to + communicate with Lagoon via SSH/API. + properties: + apiHost: + type: string + command: + type: string + id: + type: string + name: + type: string + service: + type: string + sshHost: + type: string + sshPort: + type: string + required: + - id + type: object + type: object + project: + type: string + severity: + type: string + uuid: + type: string + type: object + type: object + type: object served: true storage: true status: diff --git a/config/crd/bases/lagoon.amazee.io_lagoontasks.yaml b/config/crd/bases/lagoon.amazee.io_lagoontasks.yaml index 0ce34a89..3c6c203c 100644 --- a/config/crd/bases/lagoon.amazee.io_lagoontasks.yaml +++ b/config/crd/bases/lagoon.amazee.io_lagoontasks.yaml @@ -1,10 +1,10 @@ --- -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.2.4 + controller-gen.kubebuilder.io/version: v0.6.2 creationTimestamp: null name: lagoontasks.lagoon.amazee.io spec: @@ -15,412 +15,412 @@ spec: plural: lagoontasks singular: lagoontask scope: Namespaced - validation: - openAPIV3Schema: - description: LagoonTask is the Schema for the lagoontasks API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: LagoonTaskSpec defines the desired state of LagoonTask - properties: - advancedTask: - description: LagoonAdvancedTaskInfo defines what an advanced task can - use for the creation of the pod. - properties: - JSONPayload: - type: string - runnerImage: - type: string - type: object - environment: - description: LagoonTaskEnvironment defines the lagoon environment information. - properties: - environmentType: - type: string - id: - type: string - name: - type: string - openshiftProjectName: - type: string - project: - type: string - required: - - environmentType - - id - - name - - openshiftProjectName - - project - type: object - key: - description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - Important: Run "make" to regenerate code after modifying this file' - type: string - misc: - description: LagoonMiscInfo defines the resource or backup information - for a misc task. - properties: - backup: - description: LagoonMiscBackupInfo defines the information for a - backup. - properties: - backupId: - type: string - id: - type: string - source: - type: string - required: - - backupId - - id - - source - type: object - id: - type: string - miscResource: - format: byte - type: string - name: - type: string - required: - - id - type: object - project: - description: LagoonTaskProject defines the lagoon project information. - properties: - id: - type: string - name: - type: string - required: - - id - - name - type: object - task: - description: LagoonTaskInfo defines what a task can use to communicate - with Lagoon via SSH/API. - properties: - apiHost: - type: string - command: - type: string - id: - type: string - name: - type: string - service: - type: string - sshHost: - type: string - sshPort: - type: string - required: - - id - type: object - type: object - status: - description: LagoonTaskStatus defines the observed state of LagoonTask - properties: - conditions: - description: 'INSERT ADDITIONAL STATUS FIELD - define observed state - of cluster Important: Run "make" to regenerate code after modifying - this file' - items: - description: LagoonTaskConditions defines the observed conditions - of task pods. + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: LagoonTask is the Schema for the lagoontasks API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: LagoonTaskSpec defines the desired state of LagoonTask + properties: + advancedTask: + description: LagoonAdvancedTaskInfo defines what an advanced task + can use for the creation of the pod. properties: - lastTransitionTime: + JSONPayload: type: string - status: + runnerImage: type: string - type: - description: TaskStatusType const for the status type + type: object + environment: + description: LagoonTaskEnvironment defines the lagoon environment + information. + properties: + environmentType: + type: string + id: + type: string + name: + type: string + openshiftProjectName: + type: string + project: type: string required: - - lastTransitionTime - - status - - type + - environmentType + - id + - name + - openshiftProjectName + - project type: object - type: array - log: - format: byte - type: string - type: object - statusMessages: - description: LagoonStatusMessages is where unsent messages are stored for - re-sending. - properties: - buildLogMessage: - description: LagoonLog is used to sendToLagoonLogs messaging queue this - is general logging information - properties: - event: - type: string - message: - type: string - meta: - description: LagoonLogMeta is the metadata that is used by logging - in Lagoon. - properties: - advancedData: - type: string - branchName: - type: string - buildName: - type: string - buildPhase: - type: string - endTime: - type: string - environment: - type: string - environmentId: - type: integer - jobName: - type: string - jobStatus: - type: string - key: - type: string - logLink: - type: string - monitoringUrls: - items: + key: + description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + Important: Run "make" to regenerate code after modifying this file' + type: string + misc: + description: LagoonMiscInfo defines the resource or backup information + for a misc task. + properties: + backup: + description: LagoonMiscBackupInfo defines the information for + a backup. + properties: + backupId: type: string - type: array - project: - type: string - projectId: - type: integer - projectName: - type: string - remoteId: - type: string - route: - type: string - routes: - items: + id: type: string - type: array - services: - items: + source: type: string - type: array - startTime: - type: string - task: - description: LagoonTaskInfo defines what a task can use to communicate - with Lagoon via SSH/API. - properties: - apiHost: - type: string - command: - type: string - id: - type: string - name: - type: string - service: - type: string - sshHost: - type: string - sshPort: - type: string - required: - - id - type: object - type: object - project: - type: string - severity: - type: string - uuid: - type: string - type: object - environmentMessage: - description: LagoonMessage is used for sending build info back to Lagoon - messaging queue to update the environment or deployment - properties: - meta: - description: LagoonLogMeta is the metadata that is used by logging - in Lagoon. + required: + - backupId + - id + - source + type: object + id: + type: string + miscResource: + format: byte + type: string + name: + type: string + required: + - id + type: object + project: + description: LagoonTaskProject defines the lagoon project information. + properties: + id: + type: string + name: + type: string + required: + - id + - name + type: object + task: + description: LagoonTaskInfo defines what a task can use to communicate + with Lagoon via SSH/API. + properties: + apiHost: + type: string + command: + type: string + id: + type: string + name: + type: string + service: + type: string + sshHost: + type: string + sshPort: + type: string + required: + - id + type: object + type: object + status: + description: LagoonTaskStatus defines the observed state of LagoonTask + properties: + conditions: + description: 'INSERT ADDITIONAL STATUS FIELD - define observed state + of cluster Important: Run "make" to regenerate code after modifying + this file' + items: + description: LagoonTaskConditions defines the observed conditions + of task pods. properties: - advancedData: + lastTransitionTime: type: string - branchName: + status: type: string - buildName: + type: + description: TaskStatusType const for the status type type: string - buildPhase: - type: string - endTime: - type: string - environment: - type: string - environmentId: - type: integer - jobName: - type: string - jobStatus: - type: string - key: - type: string - logLink: - type: string - monitoringUrls: - items: + required: + - lastTransitionTime + - status + - type + type: object + type: array + log: + format: byte + type: string + type: object + statusMessages: + description: LagoonStatusMessages is where unsent messages are stored + for re-sending. + properties: + buildLogMessage: + description: LagoonLog is used to sendToLagoonLogs messaging queue + this is general logging information + properties: + event: + type: string + message: + type: string + meta: + description: LagoonLogMeta is the metadata that is used by logging + in Lagoon. + properties: + advancedData: type: string - type: array - project: - type: string - projectId: - type: integer - projectName: - type: string - remoteId: - type: string - route: - type: string - routes: - items: + branchName: type: string - type: array - services: - items: + buildName: type: string - type: array - startTime: - type: string - task: - description: LagoonTaskInfo defines what a task can use to communicate - with Lagoon via SSH/API. - properties: - apiHost: - type: string - command: - type: string - id: - type: string - name: - type: string - service: + buildPhase: + type: string + endTime: + type: string + environment: + type: string + environmentId: + type: integer + jobName: + type: string + jobStatus: + type: string + key: + type: string + logLink: + type: string + monitoringUrls: + items: type: string - sshHost: + type: array + project: + type: string + projectId: + type: integer + projectName: + type: string + remoteId: + type: string + route: + type: string + routes: + items: type: string - sshPort: + type: array + services: + items: type: string - required: - - id - type: object - type: object - namespace: - type: string - type: - type: string - type: object - statusMessage: - description: LagoonLog is used to sendToLagoonLogs messaging queue this - is general logging information - properties: - event: - type: string - message: - type: string - meta: - description: LagoonLogMeta is the metadata that is used by logging - in Lagoon. - properties: - advancedData: - type: string - branchName: - type: string - buildName: - type: string - buildPhase: - type: string - endTime: - type: string - environment: - type: string - environmentId: - type: integer - jobName: - type: string - jobStatus: - type: string - key: - type: string - logLink: - type: string - monitoringUrls: - items: + type: array + startTime: type: string - type: array - project: - type: string - projectId: - type: integer - projectName: - type: string - remoteId: - type: string - route: - type: string - routes: - items: + task: + description: LagoonTaskInfo defines what a task can use to + communicate with Lagoon via SSH/API. + properties: + apiHost: + type: string + command: + type: string + id: + type: string + name: + type: string + service: + type: string + sshHost: + type: string + sshPort: + type: string + required: + - id + type: object + type: object + project: + type: string + severity: + type: string + uuid: + type: string + type: object + environmentMessage: + description: LagoonMessage is used for sending build info back to + Lagoon messaging queue to update the environment or deployment + properties: + meta: + description: LagoonLogMeta is the metadata that is used by logging + in Lagoon. + properties: + advancedData: type: string - type: array - services: - items: + branchName: type: string - type: array - startTime: - type: string - task: - description: LagoonTaskInfo defines what a task can use to communicate - with Lagoon via SSH/API. - properties: - apiHost: - type: string - command: + buildName: + type: string + buildPhase: + type: string + endTime: + type: string + environment: + type: string + environmentId: + type: integer + jobName: + type: string + jobStatus: + type: string + key: + type: string + logLink: + type: string + monitoringUrls: + items: type: string - id: + type: array + project: + type: string + projectId: + type: integer + projectName: + type: string + remoteId: + type: string + route: + type: string + routes: + items: type: string - name: + type: array + services: + items: type: string - service: + type: array + startTime: + type: string + task: + description: LagoonTaskInfo defines what a task can use to + communicate with Lagoon via SSH/API. + properties: + apiHost: + type: string + command: + type: string + id: + type: string + name: + type: string + service: + type: string + sshHost: + type: string + sshPort: + type: string + required: + - id + type: object + type: object + namespace: + type: string + type: + type: string + type: object + statusMessage: + description: LagoonLog is used to sendToLagoonLogs messaging queue + this is general logging information + properties: + event: + type: string + message: + type: string + meta: + description: LagoonLogMeta is the metadata that is used by logging + in Lagoon. + properties: + advancedData: + type: string + branchName: + type: string + buildName: + type: string + buildPhase: + type: string + endTime: + type: string + environment: + type: string + environmentId: + type: integer + jobName: + type: string + jobStatus: + type: string + key: + type: string + logLink: + type: string + monitoringUrls: + items: type: string - sshHost: + type: array + project: + type: string + projectId: + type: integer + projectName: + type: string + remoteId: + type: string + route: + type: string + routes: + items: type: string - sshPort: + type: array + services: + items: type: string - required: - - id - type: object - type: object - project: - type: string - severity: - type: string - uuid: - type: string - type: object - type: object - type: object - version: v1alpha1 - versions: - - name: v1alpha1 + type: array + startTime: + type: string + task: + description: LagoonTaskInfo defines what a task can use to + communicate with Lagoon via SSH/API. + properties: + apiHost: + type: string + command: + type: string + id: + type: string + name: + type: string + service: + type: string + sshHost: + type: string + sshPort: + type: string + required: + - id + type: object + type: object + project: + type: string + severity: + type: string + uuid: + type: string + type: object + type: object + type: object served: true storage: true status: diff --git a/config/crd/patches/cainjection_in_lagoonbuilds.yaml b/config/crd/patches/cainjection_in_lagoonbuilds.yaml index 902829e4..acb6f0fd 100644 --- a/config/crd/patches/cainjection_in_lagoonbuilds.yaml +++ b/config/crd/patches/cainjection_in_lagoonbuilds.yaml @@ -1,6 +1,6 @@ # The following patch adds a directive for certmanager to inject CA into the CRD # CRD conversion requires k8s 1.13 or later. -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: diff --git a/config/crd/patches/cainjection_in_lagoontasks.yaml b/config/crd/patches/cainjection_in_lagoontasks.yaml index 7e29f652..e9c94266 100644 --- a/config/crd/patches/cainjection_in_lagoontasks.yaml +++ b/config/crd/patches/cainjection_in_lagoontasks.yaml @@ -1,6 +1,6 @@ # The following patch adds a directive for certmanager to inject CA into the CRD # CRD conversion requires k8s 1.13 or later. -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: diff --git a/config/crd/patches/webhook_in_lagoonbuilds.yaml b/config/crd/patches/webhook_in_lagoonbuilds.yaml index 3388a6b7..ab00924a 100644 --- a/config/crd/patches/webhook_in_lagoonbuilds.yaml +++ b/config/crd/patches/webhook_in_lagoonbuilds.yaml @@ -1,17 +1,18 @@ # The following patch enables conversion webhook for CRD # CRD conversion requires k8s 1.13 or later. -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: lagoonbuilds.lagoon.amazee.io spec: conversion: strategy: Webhook - webhookClientConfig: - # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank, - # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager) - caBundle: Cg== - service: - namespace: system - name: webhook-service - path: /convert + webhook: + clientConfig: + # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank, + # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager) + caBundle: Cg== + service: + namespace: system + name: webhook-service + path: /convert diff --git a/config/crd/patches/webhook_in_lagoontasks.yaml b/config/crd/patches/webhook_in_lagoontasks.yaml index 18abefe9..e76040ef 100644 --- a/config/crd/patches/webhook_in_lagoontasks.yaml +++ b/config/crd/patches/webhook_in_lagoontasks.yaml @@ -1,17 +1,18 @@ # The following patch enables conversion webhook for CRD # CRD conversion requires k8s 1.13 or later. -apiVersion: apiextensions.k8s.io/v1beta1 +apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: name: lagoontasks.lagoon.amazee.io spec: conversion: strategy: Webhook - webhookClientConfig: - # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank, - # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager) - caBundle: Cg== - service: - namespace: system - name: webhook-service - path: /convert + webhook: + clientConfig: + # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank, + # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager) + caBundle: Cg== + service: + namespace: system + name: webhook-service + path: /convert diff --git a/config/default/webhookcainjection_patch.yaml b/config/default/webhookcainjection_patch.yaml index 7e79bf99..02ab515d 100644 --- a/config/default/webhookcainjection_patch.yaml +++ b/config/default/webhookcainjection_patch.yaml @@ -1,13 +1,13 @@ # This patch add annotation to admission webhook config and # the variables $(CERTIFICATE_NAMESPACE) and $(CERTIFICATE_NAME) will be substituted by kustomize. -apiVersion: admissionregistration.k8s.io/v1beta1 +apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: name: mutating-webhook-configuration annotations: cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) --- -apiVersion: admissionregistration.k8s.io/v1beta1 +apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: name: validating-webhook-configuration diff --git a/controllers/controller_predicates.go b/controllers/controller_predicates.go index f3b278d8..36935e58 100644 --- a/controllers/controller_predicates.go +++ b/controllers/controller_predicates.go @@ -18,13 +18,13 @@ type PodPredicates struct { // Create is used when a creation event is received by the controller. func (p PodPredicates) Create(e event.CreateEvent) bool { - if controller, ok := e.Meta.GetLabels()["lagoon.sh/controller"]; ok { + if controller, ok := e.Object.GetLabels()["lagoon.sh/controller"]; ok { if controller == p.ControllerNamespace { - if value, ok := e.Meta.GetLabels()["lagoon.sh/buildName"]; ok { + if value, ok := e.Object.GetLabels()["lagoon.sh/buildName"]; ok { match, _ := regexp.MatchString("^lagoon-build", value) return match } - if value, ok := e.Meta.GetLabels()["lagoon.sh/jobType"]; ok { + if value, ok := e.Object.GetLabels()["lagoon.sh/jobType"]; ok { if value == "task" { return true } @@ -36,13 +36,13 @@ func (p PodPredicates) Create(e event.CreateEvent) bool { // Delete is used when a deletion event is received by the controller. func (p PodPredicates) Delete(e event.DeleteEvent) bool { - if controller, ok := e.Meta.GetLabels()["lagoon.sh/controller"]; ok { + if controller, ok := e.Object.GetLabels()["lagoon.sh/controller"]; ok { if controller == p.ControllerNamespace { - if value, ok := e.Meta.GetLabels()["lagoon.sh/buildName"]; ok { + if value, ok := e.Object.GetLabels()["lagoon.sh/buildName"]; ok { match, _ := regexp.MatchString("^lagoon-build", value) return match } - if value, ok := e.Meta.GetLabels()["lagoon.sh/jobType"]; ok { + if value, ok := e.Object.GetLabels()["lagoon.sh/jobType"]; ok { if value == "task" { return true } @@ -54,16 +54,16 @@ func (p PodPredicates) Delete(e event.DeleteEvent) bool { // Update is used when an update event is received by the controller. func (p PodPredicates) Update(e event.UpdateEvent) bool { - if controller, ok := e.MetaOld.GetLabels()["lagoon.sh/controller"]; ok { + if controller, ok := e.ObjectOld.GetLabels()["lagoon.sh/controller"]; ok { if controller == p.ControllerNamespace { - if _, okOld := e.MetaOld.GetLabels()["lagoon.sh/buildName"]; okOld { - if value, ok := e.MetaNew.GetLabels()["lagoon.sh/buildName"]; ok { + if _, okOld := e.ObjectOld.GetLabels()["lagoon.sh/buildName"]; okOld { + if value, ok := e.ObjectNew.GetLabels()["lagoon.sh/buildName"]; ok { match, _ := regexp.MatchString("^lagoon-build", value) return match } } - if _, ok := e.MetaOld.GetLabels()["lagoon.sh/jobType"]; ok { - if value, ok := e.MetaNew.GetLabels()["lagoon.sh/jobType"]; ok { + if _, ok := e.ObjectOld.GetLabels()["lagoon.sh/jobType"]; ok { + if value, ok := e.ObjectNew.GetLabels()["lagoon.sh/jobType"]; ok { if value == "task" { return true } @@ -76,13 +76,13 @@ func (p PodPredicates) Update(e event.UpdateEvent) bool { // Generic is used when any other event is received by the controller. func (p PodPredicates) Generic(e event.GenericEvent) bool { - if controller, ok := e.Meta.GetLabels()["lagoon.sh/controller"]; ok { + if controller, ok := e.Object.GetLabels()["lagoon.sh/controller"]; ok { if controller == p.ControllerNamespace { - if value, ok := e.Meta.GetLabels()["lagoon.sh/buildName"]; ok { + if value, ok := e.Object.GetLabels()["lagoon.sh/buildName"]; ok { match, _ := regexp.MatchString("^lagoon-build", value) return match } - if value, ok := e.Meta.GetLabels()["lagoon.sh/jobType"]; ok { + if value, ok := e.Object.GetLabels()["lagoon.sh/jobType"]; ok { if value == "task" { return true } @@ -101,7 +101,7 @@ type BuildPredicates struct { // Create is used when a creation event is received by the controller. func (b BuildPredicates) Create(e event.CreateEvent) bool { - if controller, ok := e.Meta.GetLabels()["lagoon.sh/controller"]; ok { + if controller, ok := e.Object.GetLabels()["lagoon.sh/controller"]; ok { if controller == b.ControllerNamespace { return true } @@ -111,7 +111,7 @@ func (b BuildPredicates) Create(e event.CreateEvent) bool { // Delete is used when a deletion event is received by the controller. func (b BuildPredicates) Delete(e event.DeleteEvent) bool { - if controller, ok := e.Meta.GetLabels()["lagoon.sh/controller"]; ok { + if controller, ok := e.Object.GetLabels()["lagoon.sh/controller"]; ok { if controller == b.ControllerNamespace { return true } @@ -121,7 +121,7 @@ func (b BuildPredicates) Delete(e event.DeleteEvent) bool { // Update is used when an update event is received by the controller. func (b BuildPredicates) Update(e event.UpdateEvent) bool { - if controller, ok := e.MetaOld.GetLabels()["lagoon.sh/controller"]; ok { + if controller, ok := e.ObjectOld.GetLabels()["lagoon.sh/controller"]; ok { if controller == b.ControllerNamespace { return true } @@ -131,7 +131,7 @@ func (b BuildPredicates) Update(e event.UpdateEvent) bool { // Generic is used when any other event is received by the controller. func (b BuildPredicates) Generic(e event.GenericEvent) bool { - if controller, ok := e.Meta.GetLabels()["lagoon.sh/controller"]; ok { + if controller, ok := e.Object.GetLabels()["lagoon.sh/controller"]; ok { if controller == b.ControllerNamespace { return true } @@ -148,7 +148,7 @@ type TaskPredicates struct { // Create is used when a creation event is received by the controller. func (t TaskPredicates) Create(e event.CreateEvent) bool { - if controller, ok := e.Meta.GetLabels()["lagoon.sh/controller"]; ok { + if controller, ok := e.Object.GetLabels()["lagoon.sh/controller"]; ok { if controller == t.ControllerNamespace { return true } @@ -158,7 +158,7 @@ func (t TaskPredicates) Create(e event.CreateEvent) bool { // Delete is used when a deletion event is received by the controller. func (t TaskPredicates) Delete(e event.DeleteEvent) bool { - if controller, ok := e.Meta.GetLabels()["lagoon.sh/controller"]; ok { + if controller, ok := e.Object.GetLabels()["lagoon.sh/controller"]; ok { if controller == t.ControllerNamespace { return true } @@ -168,7 +168,7 @@ func (t TaskPredicates) Delete(e event.DeleteEvent) bool { // Update is used when an update event is received by the controller. func (t TaskPredicates) Update(e event.UpdateEvent) bool { - if controller, ok := e.MetaOld.GetLabels()["lagoon.sh/controller"]; ok { + if controller, ok := e.ObjectOld.GetLabels()["lagoon.sh/controller"]; ok { if controller == t.ControllerNamespace { return true } @@ -178,7 +178,7 @@ func (t TaskPredicates) Update(e event.UpdateEvent) bool { // Generic is used when any other event is received by the controller. func (t TaskPredicates) Generic(e event.GenericEvent) bool { - if controller, ok := e.Meta.GetLabels()["lagoon.sh/controller"]; ok { + if controller, ok := e.Object.GetLabels()["lagoon.sh/controller"]; ok { if controller == t.ControllerNamespace { return true } diff --git a/controllers/lagoonbuild_controller.go b/controllers/lagoonbuild_controller.go index 7ff47aec..4f3f76ad 100644 --- a/controllers/lagoonbuild_controller.go +++ b/controllers/lagoonbuild_controller.go @@ -80,8 +80,7 @@ type LagoonBuildReconciler struct { // +kubebuilder:rbac:groups="*",resources="*",verbs="*" // Reconcile runs when a request comes through -func (r *LagoonBuildReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { - ctx := context.Background() +func (r *LagoonBuildReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { opLog := r.Log.WithValues("lagoonbuild", req.NamespacedName) // your logic here @@ -147,7 +146,7 @@ func (r *LagoonBuildReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) "finalizers": lagoonBuild.ObjectMeta.Finalizers, }, }) - if err := r.Patch(ctx, &lagoonBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, &lagoonBuild, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { return ctrl.Result{}, ignoreNotFound(err) } } @@ -209,7 +208,7 @@ func (r *LagoonBuildReconciler) createNamespaceBuild(ctx context.Context, // the `lagoon.sh/buildStatus = Pending` now // so end this reconcile process pendingBuilds := &lagoonv1alpha1.LagoonBuildList{} - return ctrl.Result{}, cancelExtraBuilds(ctx, r, opLog, pendingBuilds, namespace.ObjectMeta.Name, string(lagoonv1alpha1.BuildStatusPending)) + return ctrl.Result{}, cancelExtraBuilds(ctx, r.Client, opLog, pendingBuilds, namespace.ObjectMeta.Name, string(lagoonv1alpha1.BuildStatusPending)) // return ctrl.Result{}, nil } diff --git a/controllers/lagoonbuild_deletionhandlers.go b/controllers/lagoonbuild_deletionhandlers.go index d749df14..48c97317 100644 --- a/controllers/lagoonbuild_deletionhandlers.go +++ b/controllers/lagoonbuild_deletionhandlers.go @@ -141,7 +141,7 @@ func (r *LagoonBuildReconciler) deleteExternalResources( }, }, }) - if err := r.Patch(ctx, pendingBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, pendingBuild, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { opLog.Error(err, fmt.Sprintf("Unable to update pending build to running status")) return nil } @@ -195,7 +195,7 @@ Build cancelled }, }, }) - if err := r.Patch(ctx, &lagoonBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, &lagoonBuild, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { opLog.Error(err, fmt.Sprintf("Unable to update build status")) } // get the configmap for lagoon-env so we can use it for updating the deployment in lagoon @@ -425,7 +425,7 @@ func (r *LagoonBuildReconciler) updateEnvironmentMessage(ctx context.Context, "environmentMessage": envMessage, }, }) - if err := r.Patch(ctx, lagoonBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, lagoonBuild, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { return fmt.Errorf("Unable to update status condition: %v", err) } return nil @@ -447,7 +447,7 @@ func (r *LagoonBuildReconciler) updateBuildStatusMessage(ctx context.Context, "statusMessage": statusMessage, }, }) - if err := r.Patch(ctx, lagoonBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, lagoonBuild, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { return fmt.Errorf("Unable to update status condition: %v", err) } return nil @@ -469,7 +469,7 @@ func (r *LagoonBuildReconciler) removeBuildPendingMessageStatus(ctx context.Cont }, "statusMessages": nil, }) - if err := r.Patch(ctx, lagoonBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, lagoonBuild, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { return fmt.Errorf("Unable to update status condition: %v", err) } } @@ -493,7 +493,7 @@ func (r *LagoonBuildReconciler) updateBuildLogMessage(ctx context.Context, "buildLogMessage": buildMessage, }, }) - if err := r.Patch(ctx, lagoonBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, lagoonBuild, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { return fmt.Errorf("Unable to update status condition: %v", err) } return nil diff --git a/controllers/lagoonbuild_helpers.go b/controllers/lagoonbuild_helpers.go index 982f8166..6f5d490d 100644 --- a/controllers/lagoonbuild_helpers.go +++ b/controllers/lagoonbuild_helpers.go @@ -40,7 +40,7 @@ func (r *LagoonBuildReconciler) updateBuildStatusCondition(ctx context.Context, "log": log, }, }) - if err := r.Patch(ctx, lagoonBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, lagoonBuild, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { return fmt.Errorf("Unable to update status condition: %v", err) } } @@ -207,7 +207,7 @@ func (r *LagoonBuildReconciler) getOrCreateNamespace(ctx context.Context, namesp "labels": nsLabels, }, }) - if err := r.Patch(ctx, namespace, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, namespace, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { return err } if err := r.Get(ctx, types.NamespacedName{Name: ns}, namespace); err != nil { @@ -931,7 +931,7 @@ Namespace is currently in terminating status - contact your Lagoon support team }, }, }) - if err := r.Patch(ctx, &lagoonBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, &lagoonBuild, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { opLog.Error(err, fmt.Sprintf("Unable to update build status")) } // get the configmap for lagoon-env so we can use it for updating the deployment in lagoon diff --git a/controllers/lagoonbuild_qoshandler.go b/controllers/lagoonbuild_qoshandler.go index 0a6f01d2..670144e3 100644 --- a/controllers/lagoonbuild_qoshandler.go +++ b/controllers/lagoonbuild_qoshandler.go @@ -117,7 +117,7 @@ func (r *LagoonBuildReconciler) whichBuildNext(ctx context.Context, opLog logr.L "finalizers": pBuild.ObjectMeta.Finalizers, }, }) - if err := r.Patch(ctx, &pBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, &pBuild, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { return err } } diff --git a/controllers/lagoonbuild_standardhandler.go b/controllers/lagoonbuild_standardhandler.go index b51482be..edda172a 100644 --- a/controllers/lagoonbuild_standardhandler.go +++ b/controllers/lagoonbuild_standardhandler.go @@ -63,7 +63,7 @@ func (r *LagoonBuildReconciler) standardBuildProcessor(ctx context.Context, "finalizers": lagoonBuild.ObjectMeta.Finalizers, }, }) - if err := r.Patch(ctx, &lagoonBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, &lagoonBuild, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { return ctrl.Result{}, err } } diff --git a/controllers/lagoonmonitor_buildhandlers.go b/controllers/lagoonmonitor_buildhandlers.go index bf0dc029..01a81ab6 100644 --- a/controllers/lagoonmonitor_buildhandlers.go +++ b/controllers/lagoonmonitor_buildhandlers.go @@ -402,7 +402,7 @@ func (r *LagoonMonitorReconciler) updateBuildStatusCondition(ctx context.Context "log": log, }, }) - if err := r.Patch(ctx, lagoonBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, lagoonBuild, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { return fmt.Errorf("Unable to update status condition: %v", err) } } @@ -425,7 +425,7 @@ func (r *LagoonMonitorReconciler) updateBuildStatusMessage(ctx context.Context, "statusMessage": statusMessage, }, }) - if err := r.Patch(ctx, lagoonBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, lagoonBuild, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { return fmt.Errorf("Unable to update status condition: %v", err) } return nil @@ -447,7 +447,7 @@ func (r *LagoonMonitorReconciler) updateEnvironmentMessage(ctx context.Context, "environmentMessage": envMessage, }, }) - if err := r.Patch(ctx, lagoonBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, lagoonBuild, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { return fmt.Errorf("Unable to update status condition: %v", err) } return nil @@ -469,7 +469,7 @@ func (r *LagoonMonitorReconciler) updateBuildLogMessage(ctx context.Context, "buildLogMessage": buildMessage, }, }) - if err := r.Patch(ctx, lagoonBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, lagoonBuild, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { return fmt.Errorf("Unable to update status condition: %v", err) } return nil @@ -491,7 +491,7 @@ func (r *LagoonMonitorReconciler) removeBuildPendingMessageStatus(ctx context.Co }, "statusMessages": nil, }) - if err := r.Patch(ctx, lagoonBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, lagoonBuild, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { return fmt.Errorf("Unable to update status condition: %v", err) } } @@ -512,7 +512,7 @@ func (r *LagoonMonitorReconciler) updateRunningDeploymentBuildLogs( // we only have 1 container at the moment in a buildpod anyway so it doesn't matter // if we do move to multi container builds, then worry about it for _, container := range jobPod.Spec.Containers { - cLogs, err := getContainerLogs(container.Name, req) + cLogs, err := getContainerLogs(ctx, container.Name, req) if err != nil { opLog.Error(err, fmt.Sprintf("Unable to retrieve logs from build pod")) // log the error, but just continue @@ -562,7 +562,7 @@ func (r *LagoonMonitorReconciler) updateDeploymentWithLogs( // we only have 1 container at the moment in a buildpod anyway so it doesn't matter // if we do move to multi container builds, then worry about it for _, container := range jobPod.Spec.Containers { - cLogs, err := getContainerLogs(container.Name, req) + cLogs, err := getContainerLogs(ctx, container.Name, req) if err != nil { opLog.Error(err, fmt.Sprintf("Unable to retrieve logs from build pod")) // log the error, but just continue @@ -582,7 +582,7 @@ Build cancelled }, }, }) - if err := r.Patch(ctx, &lagoonBuild, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, &lagoonBuild, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { opLog.Error(err, fmt.Sprintf("Unable to update resource")) } r.updateBuildStatusCondition(ctx, &lagoonBuild, lagoonv1alpha1.LagoonBuildConditions{ diff --git a/controllers/lagoonmonitor_controller.go b/controllers/lagoonmonitor_controller.go index 76a8885f..980a9a4d 100644 --- a/controllers/lagoonmonitor_controller.go +++ b/controllers/lagoonmonitor_controller.go @@ -55,8 +55,7 @@ var failureStates = []string{ // +kubebuilder:rbac:groups="*",resources="*",verbs="*" // Reconcile runs when a request comes through -func (r *LagoonMonitorReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { - ctx := context.Background() +func (r *LagoonMonitorReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { opLog := r.Log.WithValues("lagoonmonitor", req.NamespacedName) var jobPod corev1.Pod @@ -125,7 +124,7 @@ func (r *LagoonMonitorReconciler) Reconcile(req ctrl.Request) (ctrl.Result, erro } // if we have no running builds, then check for any pending builds if len(runningBuilds.Items) == 0 { - return ctrl.Result{}, cancelExtraBuilds(ctx, r, opLog, pendingBuilds, req.Namespace, "Running") + return ctrl.Result{}, cancelExtraBuilds(ctx, r.Client, opLog, pendingBuilds, req.Namespace, "Running") } } return ctrl.Result{}, nil @@ -143,7 +142,7 @@ func (r *LagoonMonitorReconciler) SetupWithManager(mgr ctrl.Manager) error { } // getContainerLogs grabs the logs from a given container -func getContainerLogs(containerName string, request ctrl.Request) ([]byte, error) { +func getContainerLogs(ctx context.Context, containerName string, request ctrl.Request) ([]byte, error) { restCfg, err := config.GetConfig() if err != nil { return nil, fmt.Errorf("unable to get config: %v", err) @@ -153,7 +152,7 @@ func getContainerLogs(containerName string, request ctrl.Request) ([]byte, error return nil, fmt.Errorf("unable to create client: %v", err) } req := clientset.CoreV1().Pods(request.Namespace).GetLogs(request.Name, &corev1.PodLogOptions{Container: containerName}) - podLogs, err := req.Stream() + podLogs, err := req.Stream(ctx) if err != nil { return nil, fmt.Errorf("error in opening stream: %v", err) } diff --git a/controllers/lagoonmonitor_taskhandlers.go b/controllers/lagoonmonitor_taskhandlers.go index 62b6d5ed..e5a92a1e 100644 --- a/controllers/lagoonmonitor_taskhandlers.go +++ b/controllers/lagoonmonitor_taskhandlers.go @@ -93,7 +93,7 @@ func (r *LagoonMonitorReconciler) handleTaskMonitor(ctx context.Context, opLog l // we only have 1 container at the moment in a buildpod anyway so it doesn't matter // if we do move to multi container builds, then worry about it for _, container := range jobPod.Spec.Containers { - cLogs, err := getContainerLogs(container.Name, req) + cLogs, err := getContainerLogs(ctx, container.Name, req) if err != nil { opLog.Error(err, fmt.Sprintf("Unable to retrieve logs from task pod")) // log the error, but just continue @@ -311,7 +311,7 @@ func (r *LagoonMonitorReconciler) updateTaskStatusCondition(ctx context.Context, "log": log, }, }) - if err := r.Patch(ctx, lagoonTask, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, lagoonTask, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { return fmt.Errorf("Unable to update status condition: %v", err) } } @@ -333,7 +333,7 @@ func (r *LagoonMonitorReconciler) updateTaskEnvironmentMessage(ctx context.Conte "environmentMessage": envMessage, }, }) - if err := r.Patch(ctx, lagoonTask, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, lagoonTask, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { return fmt.Errorf("Unable to update status condition: %v", err) } return nil @@ -354,7 +354,7 @@ func (r *LagoonMonitorReconciler) lagoonTask(ctx context.Context, "buildLogMessage": taskMessage, }, }) - if err := r.Patch(ctx, lagoonTask, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, lagoonTask, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { return fmt.Errorf("Unable to update status condition: %v", err) } return nil @@ -375,7 +375,7 @@ func (r *LagoonMonitorReconciler) updateTaskStatusMessage(ctx context.Context, "statusMessage": statusMessage, }, }) - if err := r.Patch(ctx, lagoonTask, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, lagoonTask, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { return fmt.Errorf("Unable to update status condition: %v", err) } return nil @@ -395,7 +395,7 @@ func (r *LagoonMonitorReconciler) removeTaskPendingMessageStatus(ctx context.Con }, "statusMessages": nil, }) - if err := r.Patch(ctx, lagoonTask, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, lagoonTask, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { return fmt.Errorf("Unable to update status condition: %v", err) } } diff --git a/controllers/lagoontask_controller.go b/controllers/lagoontask_controller.go index 400d5290..cad63777 100644 --- a/controllers/lagoontask_controller.go +++ b/controllers/lagoontask_controller.go @@ -62,8 +62,7 @@ var ( // +kubebuilder:rbac:groups=lagoon.amazee.io,resources=lagoontasks/status,verbs=get;update;patch // Reconcile runs when a request comes through -func (r *LagoonTaskReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { - ctx := context.Background() +func (r *LagoonTaskReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { opLog := r.Log.WithValues("lagoontask", req.NamespacedName) // your logic here @@ -100,7 +99,7 @@ func (r *LagoonTaskReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) "finalizers": lagoonTask.ObjectMeta.Finalizers, }, }) - if err := r.Patch(ctx, &lagoonTask, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, &lagoonTask, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { return ctrl.Result{}, err } } @@ -397,7 +396,7 @@ func (r *LagoonTaskReconciler) createStandardTask(ctx context.Context, lagoonTas "finalizers": lagoonTask.ObjectMeta.Finalizers, }, }) - if err := r.Patch(ctx, lagoonTask, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := r.Patch(ctx, lagoonTask, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { return err } } diff --git a/controllers/suite_test.go b/controllers/suite_test.go index 39733b70..0ccac2c9 100644 --- a/controllers/suite_test.go +++ b/controllers/suite_test.go @@ -27,6 +27,7 @@ import ( "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/envtest" + "sigs.k8s.io/controller-runtime/pkg/envtest/printer" logf "sigs.k8s.io/controller-runtime/pkg/log" "sigs.k8s.io/controller-runtime/pkg/log/zap" // +kubebuilder:scaffold:imports @@ -44,11 +45,11 @@ func TestAPIs(t *testing.T) { RunSpecsWithDefaultAndCustomReporters(t, "Controller Suite", - []Reporter{envtest.NewlineReporter{}}) + []Reporter{printer.NewlineReporter{}}) } var _ = BeforeSuite(func(done Done) { - logf.SetLogger(zap.LoggerTo(GinkgoWriter, true)) + logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) By("bootstrapping test environment") testEnv = &envtest.Environment{ diff --git a/go.mod b/go.mod index 92136325..efb2ace1 100644 --- a/go.mod +++ b/go.mod @@ -1,25 +1,31 @@ module github.com/amazeeio/lagoon-kbd -go 1.13 +go 1.16 require ( + cloud.google.com/go v0.81.0 // indirect github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 // indirect github.com/cheshir/go-mq v1.0.2 github.com/fsouza/go-dockerclient v1.6.5 // indirect - github.com/go-logr/logr v0.1.0 + github.com/go-logr/logr v0.4.0 + github.com/google/go-cmp v0.5.6 // indirect github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2 // indirect + github.com/mitchellh/mapstructure v1.4.1 // indirect github.com/mittwald/goharbor-client/v3 v3.3.0 - github.com/onsi/ginkgo v1.10.1 - github.com/onsi/gomega v1.7.0 + github.com/onsi/ginkgo v1.16.4 + github.com/onsi/gomega v1.14.0 github.com/openshift/api v3.9.0+incompatible github.com/tiago4orion/conjure v0.0.0-20150908101743-93cb30b9d218 // indirect github.com/xhit/go-str2duration/v2 v2.0.0 + golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602 // indirect + golang.org/x/tools v0.1.5 // indirect + google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect gopkg.in/matryer/try.v1 v1.0.0-20150601225556-312d2599e12e gopkg.in/robfig/cron.v2 v2.0.0-20150107220207-be2e0b0deed5 - k8s.io/api v0.0.0-20190918155943-95b840bb6a1f - k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655 - k8s.io/client-go v0.0.0-20190918160344-1fbdaa4c8d90 - sigs.k8s.io/controller-runtime v0.4.0 + k8s.io/api v0.21.3 + k8s.io/apimachinery v0.21.3 + k8s.io/client-go v0.21.3 + sigs.k8s.io/controller-runtime v0.9.6 ) // Fixes for AppID diff --git a/go.sum b/go.sum index 6bb93e63..e930e5bc 100644 --- a/go.sum +++ b/go.sum @@ -1,17 +1,53 @@ bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0 h1:ROfEUZz+Gh5pa62DJWXSaonyu3StP6EA6lPEXPI6mCo= cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= +cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0 h1:at8Tk2zUz63cLPR0JPWm5vp77pEZmzxEQBEfRKn1VV8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= -github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= -github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA= -github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= -github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk= +github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= +github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw= +github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A= +github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74= +github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k= +github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= +github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Microsoft/go-winio v0.4.15-0.20190919025122-fc70bd9a86b5/go.mod h1:tTuCMEN+UleMWgg9dVx4Hu52b1bJo+59jBh3ajtinzw= @@ -20,29 +56,53 @@ github.com/Microsoft/go-winio v0.4.15-0.20200113171025-3fe6c5262873/go.mod h1:tT github.com/Microsoft/hcsshim v0.8.7 h1:ptnOoufxGSzauVTsdE+wMYnCWA301PdoN4xg5oRdZpg= github.com/Microsoft/hcsshim v0.8.7/go.mod h1:OHd7sQqRFrYd3RmSgbgji+ctCwkbq2wbEYNSzOYtcBQ= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= -github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= +github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= +github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= +github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= +github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 h1:4daAzAu0S6Vi7/lbWECcX0j45yZReDZ56BQsrVBOEEY= github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0= +github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927 h1:SKI1/fuSdodxmNNyVBR8d7X/HuLnRpvvFO0AgyQk764= github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/containerd/cgroups v0.0.0-20190919134610-bf292b21730f/go.mod h1:OApqhQ4XNSNC13gXIwDjhOQxjWa/NxkwZXJ1EvqT0ko= github.com/containerd/console v0.0.0-20180822173158-c12b1e7919c1/go.mod h1:Tj/on1eG8kiEhd0+fhSDzsPAFESxzBBvdyEgyryXffw= github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= @@ -55,26 +115,26 @@ github.com/containerd/fifo v0.0.0-20190226154929-a9fb20d87448/go.mod h1:ODA38xgv github.com/containerd/go-runc v0.0.0-20180907222934-5a6d9f37cfa3/go.mod h1:IV7qH3hrUgRmyYrtgEeGWJfWbgcHL9CSRruz2Vqcph0= github.com/containerd/ttrpc v0.0.0-20190828154514-0e0f228740de/go.mod h1:PvCDdDGpgqzQIzDW1TphrGLssLDZp2GuS+X5DkEJB8o= github.com/containerd/typeurl v0.0.0-20180627222232-a93fcdb778cd/go.mod h1:Cm3kwCdlkCfMSHURc+r6fwoGH6/F1hH3S4sg0rLFWPc= -github.com/coreos/bbolt v1.3.1-coreos.6/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/etcd v3.3.15+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= +github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= +github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= +github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v1.4.2-0.20191101170500-ac7306503d23 h1:oqgGT9O61YAYvI41EBsLePOr+LE6roB0xY4gpkZuFSE= github.com/docker/docker v1.4.2-0.20191101170500-ac7306503d23/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= @@ -82,28 +142,48 @@ github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5Xh github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= +github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= +github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M= -github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/evanphx/json-patch v0.5.2/go.mod h1:ZWS5hhDbVDyob71nXKNL0+PWn6ToqBHMikGIFbs31qQ= +github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v4.11.0+incompatible h1:glyUF9yIYtMHzn8xaKw5rMhdWcwsYV8dZHIq5567/xs= +github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsouza/go-dockerclient v1.6.5 h1:vuFDnPcds3LvTWGYb9h0Rty14FLgkjHZdwLDROCdgsw= github.com/fsouza/go-dockerclient v1.6.5/go.mod h1:GOdftxWLWIbIWKbIMDroKFJzPdg6Iw7r+jX1DDZdVsA= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= -github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/zapr v0.1.0 h1:h+WVe9j6HAA01niTJPA/kKH0i7e0rLZBCwauQFcRE54= -github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= +github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc= +github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= +github.com/go-logr/zapr v0.4.0 h1:uc1uML3hRYL9/ZZPdgHS/n8Nzo+eaYL/Efxkkamf7OM= +github.com/go-logr/zapr v0.4.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI= github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik= @@ -119,13 +199,11 @@ github.com/go-openapi/errors v0.19.3/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA github.com/go-openapi/errors v0.19.6/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= github.com/go-openapi/errors v0.19.7 h1:Lcq+o0mSwCLKACMxZhreVHigB9ebghJ/lrmeaqASbjo= github.com/go-openapi/errors v0.19.7/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= @@ -145,11 +223,11 @@ github.com/go-openapi/runtime v0.19.15/go.mod h1:dhGWCTKRXlAfGnQG0ONViOZpjfg0m2g github.com/go-openapi/runtime v0.19.16/go.mod h1:5P9104EJgYcizotuXhEuUrzVc+j1RiSjahULvYmlv98= github.com/go-openapi/runtime v0.19.22 h1:vtT7gJwxIK96BVTd9Ce5OPNQfIsk+q1j/+0e98NoVXk= github.com/go-openapi/runtime v0.19.22/go.mod h1:Lm9YGCeecBnUUkFTxPC4s1+lwrkJ0pthx8YvyjCfkgk= -github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.18.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI= github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= +github.com/go-openapi/spec v0.19.5/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= github.com/go-openapi/spec v0.19.6/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= github.com/go-openapi/spec v0.19.8 h1:qAdZLh1r6QF/hI/gTq+TJTvsQUodZsM7KLqkAJdiJNg= github.com/go-openapi/spec v0.19.8/go.mod h1:Hm2Jr4jv8G1ciIAo+frC/Ft+rR2kQDh8JHKHb3gWUSk= @@ -161,7 +239,6 @@ github.com/go-openapi/strfmt v0.19.3/go.mod h1:0yX7dbo8mKIvc3XSKp7MNfxw4JytCfCD6 github.com/go-openapi/strfmt v0.19.4/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= github.com/go-openapi/strfmt v0.19.5 h1:0utjKrw+BAh8s57XE9Xz8DUBsVvPmRUB6styvl9wWIM= github.com/go-openapi/strfmt v0.19.5/go.mod h1:eftuHTlB/dI8Uq8JJOyRlieZf+WkkxUuk0dgdHXr2Qk= -github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= @@ -177,6 +254,7 @@ github.com/go-openapi/validate v0.19.11 h1:8lCr0b9lNWKjVjW/hSZZvltUy+bULl7vbnCTs github.com/go-openapi/validate v0.19.11/go.mod h1:Rzou8hA/CBw8donlS6WNEUQupNvUZ0waH08tGe6kAQ4= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= @@ -202,109 +280,196 @@ github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGt github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d h1:3PaI8p3seN09VjbTYC/QWlUZdZ1qS1zGjy7LH2Wt07I= -github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7 h1:u4bArs140e9+AfE52mFHOXVFnOSBJBRlzTHrOPLOIhE= -github.com/golang/groupcache v0.0.0-20180513044358-24b0969c4cb7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.0.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= -github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= +github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= +github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk= -github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU= -github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg= +github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= +github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.3.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= +github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= +github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= +github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= +github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= +github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= +github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= +github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= +github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= -github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= +github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= -github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ= +github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= -github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/mailru/easyjson v0.7.1 h1:mdxE1MF9o53iCb2Ghj1VfWvh7ZOwHpnVG/xwXrV90U8= github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2 h1:JAEbJn3j/FrhdWA9jW8B5ajsLIjeuEHLi8xE4fk997o= github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs= -github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= +github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= +github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= +github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= +github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.3.2 h1:mRS76wmkOn3KkKAyXDu42V+6ebnXWIztFSYGN7GeoRg= github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= @@ -312,22 +477,30 @@ github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.4.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.3.0/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.14.0 h1:ep6kpPVwmr/nTbklSx2nrLNSIO62DoYAhnPNIMhK8gI= +github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0= github.com/opencontainers/go-digest v0.0.0-20180430190053-c9281466c8b2/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= @@ -340,6 +513,7 @@ github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.m github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs= github.com/openshift/api v3.9.0+incompatible h1:fJ/KsefYuZAjmrr3+5U9yZIZbTOpVkDDLDLFresAeYs= github.com/openshift/api v3.9.0+incompatible/go.mod h1:dh9o4Fs58gpFXGSYfnVxGR9PnV53I8TW84pQaJDdGiY= +github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g= github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= @@ -347,29 +521,46 @@ github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUr github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= -github.com/prometheus/client_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740= -github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= +github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ= +github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/common v0.0.0-20181126121408-4724e9255275 h1:PnBWHBf+6L0jOqq0gIVUe6Yk0/QMZ640k6NvkxcBf+8= -github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE= -github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.5 h1:3+auTFlqw+ZaQYJARz6ArODtkaIwtvBTx3N2NehQlL8= +github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= +github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= +github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= +github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= +github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.5/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= +github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= +github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shreddedbacon/go-mq v0.0.0-20200419104937-b8e9af912ead h1:brBqfI3SWHkBhydQ4zdYbeQj/4Rq68GHO+Me8W7Fji8= github.com/shreddedbacon/go-mq v0.0.0-20200419104937-b8e9af912ead/go.mod h1:lAwW/xhfO27t6WSVHFtLdgYioymwJvQxMSH19z00/BY= @@ -377,46 +568,57 @@ github.com/shreddedbacon/goharbor-client/v3 v3.0.0-20210618042159-ceb1f437ad75 h github.com/shreddedbacon/goharbor-client/v3 v3.0.0-20210618042159-ceb1f437ad75/go.mod h1:B6DcW8mCOdRr3gYxZ5OIaM5S3P89VBNadTtrgunAj5Q= github.com/shreddedbacon/wabbit v0.0.0-20200419104837-5b7b769d7204 h1:jXml7E4X/d9v6LATMXFPCF1yW6TKrs+o5wMtYTaBdTw= github.com/shreddedbacon/wabbit v0.0.0-20200419104837-5b7b769d7204/go.mod h1:l7t6U3j3uZUYroWctp1FvWEktRMuGqx2zCcb5cd8cS8= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sirupsen/logrus v1.0.4-0.20170822132746-89742aefa4b2/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v0.0.2-0.20171109065643-2da4a54c5cee/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/cobra v1.1.1/go.mod h1:WnodtKOvamDL/PwE2M4iKs8aMDBZ5Q5klgD3qfVJQMI= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.1-0.20171106142849-4c012f6dcd95/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= +github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71 h1:2MR0pKUzlP3SGgj5NYJe/zRYDwOu9ku6YHy+Iw7l5DM= github.com/streadway/amqp v0.0.0-20200108173154-1c71cc93ed71/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/tiago4orion/conjure v0.0.0-20150908101743-93cb30b9d218 h1:tOESt7J50fPC9NqR0VdU1Zxk2zo5QYH70ap5TsU1bt4= github.com/tiago4orion/conjure v0.0.0-20150908101743-93cb30b9d218/go.mod h1:GQei++1WClbEC7AN1B9ipY1jCjzllM/7UNg0okAh/Z4= github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= +github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I= github.com/xdg/stringprep v0.0.0-20180714160509-73f8eece6fdc/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y= @@ -425,8 +627,16 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1: github.com/xeipuuv/gojsonschema v0.0.0-20180618132009-1d523034197f/go.mod h1:5yf86TLmAcydyeJq5YvxkGPE2fm/u4myDekKRoLuqhs= github.com/xhit/go-str2duration/v2 v2.0.0 h1:uFtk6FWB375bP7ewQl+/1wBcn840GPhnySOdcz/okPE= github.com/xhit/go-str2duration/v2 v2.0.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= -github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= +github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/etcd v0.5.0-alpha.5.0.20200910180754-dd1b699fc489/go.mod h1:yVHk9ub3CSBatqGNg7GRmsnfLWtoW60w4eDYfh7vHDg= go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.3.0/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= @@ -434,76 +644,158 @@ go.mongodb.org/mongo-driver v1.3.4 h1:zs/dKNwX0gYUtzwrN9lLiR15hCO0nDwQj5xXx+vjCd go.mongodb.org/mongo-driver v1.3.4/go.mod h1:MSWZXKOynuguX+JSvwP8i+58jYCXxbia8HS3gZBapIE= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI= +go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/zap v0.0.0-20180814183419-67bc79d13d15/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= +go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +go.uber.org/zap v1.18.1 h1:CSUJ2mjFszzEWt4CdKISEuChVIXGBn3lAPwkRGyVrc4= +go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= golang.org/x/crypto v0.0.0-20171113213409-9f005a07e0d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190617133340-57b3e21c3d56/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975 h1:/Tl7pH94bvbAAHBdZJT947M/+gp0+CqQXDtMRC0fseo= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200220183623-bac4c82f6975/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180112015858-5ccada7d0a7b/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190320064053-1272bf9dcd53/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc h1:gkKoSkUmnU6bpS/VhkuO27bzQeSA51uaEfbOW5dNb68= -golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200602114024-627f9648deb9 h1:pNX+40auqi2JqRfOP1akLGtYcn15TUbkhwuCO3foqqM= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602 h1:0Ja1LBD+yisY6RWM/BH7TJVXWsSjs2VwBSmvSX4HdBc= +golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180117170059-2c42eef0765b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190321052220-f7bb7a8bee54/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -512,84 +804,274 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190514135907-3a4b5fb9f71f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f h1:25KHgbfyiSm6vwQLbM3zZIe1v9p/3ea4Rz+nnM5K/i4= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3 h1:7TYNF4UdlohbFwpNH04CoPMp1cHUZgO1Ebq5r2hIjfo= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= +golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE= +golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20171227012246-e19ae1496984/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c h1:fqgJT0MGcGpPgpWU7VRdRjuArfcOvC4AoJmILihzhDg= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= +golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190617190820-da514acc4774/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= +golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= +golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gomodules.xyz/jsonpatch/v2 v2.0.1 h1:xyiBuvkD2g5n7cYzx6u2sxQvsAy4QJsZFCzGVdzOXZ0= -gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU= -gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0= -gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= -gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY= +gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= +google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= +google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= +google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= +google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= -gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/matryer/try.v1 v1.0.0-20150601225556-312d2599e12e h1:bJHzu9Qwc9wQRWJ/WVkJGAfs+riucl/tKAFNxf9pzqk= gopkg.in/matryer/try.v1 v1.0.0-20150601225556-312d2599e12e/go.mod h1:tve0rTLdGlwnXF7iBO9rbAEyeXvuuPx0n4DvXS/Nw7o= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= +gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/robfig/cron.v2 v2.0.0-20150107220207-be2e0b0deed5 h1:E846t8CnR+lv5nE+VuiKTDG/v1U2stad0QzddfJC7kY= gopkg.in/robfig/cron.v2 v2.0.0-20150107220207-be2e0b0deed5/go.mod h1:hiOFpYm0ZJbusNj2ywpbrXowU3G8U6GIQzqn2mw1UIE= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= @@ -597,55 +1079,63 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0 h1:POO/ycCATvegFmVuPpQzZFJ+pGZeX22Ufu6fibxDVjU= gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= -gopkg.in/yaml.v2 v2.0.0/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= +gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= +gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -k8s.io/api v0.0.0-20190918155943-95b840bb6a1f h1:8FRUST8oUkEI45WYKyD8ed7Ad0Kg5v11zHyPkEVb2xo= -k8s.io/api v0.0.0-20190918155943-95b840bb6a1f/go.mod h1:uWuOHnjmNrtQomJrvEBg0c0HRNyQ+8KTEERVsK0PW48= -k8s.io/apiextensions-apiserver v0.0.0-20190918161926-8f644eb6e783 h1:V6ndwCPoao1yZ52agqOKaUAl7DYWVGiXjV7ePA2i610= -k8s.io/apiextensions-apiserver v0.0.0-20190918161926-8f644eb6e783/go.mod h1:xvae1SZB3E17UpV59AWc271W/Ph25N+bjPyR63X6tPY= -k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655 h1:CS1tBQz3HOXiseWZu6ZicKX361CZLT97UFnnPx0aqBw= -k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655/go.mod h1:nL6pwRT8NgfF8TT68DBI8uEePRt89cSvoXUVqbkWHq4= -k8s.io/apiserver v0.0.0-20190918160949-bfa5e2e684ad/go.mod h1:XPCXEwhjaFN29a8NldXA901ElnKeKLrLtREO9ZhFyhg= -k8s.io/client-go v0.0.0-20190918160344-1fbdaa4c8d90 h1:mLmhKUm1X+pXu0zXMEzNsOF5E2kKFGe5o6BZBIIqA6A= -k8s.io/client-go v0.0.0-20190918160344-1fbdaa4c8d90/go.mod h1:J69/JveO6XESwVgG53q3Uz5OSfgsv4uxpScmmyYOOlk= -k8s.io/code-generator v0.0.0-20190912054826-cd179ad6a269/go.mod h1:V5BD6M4CyaN5m+VthcclXWsVcT1Hu+glwa1bi3MIsyE= -k8s.io/component-base v0.0.0-20190918160511-547f6c5d7090/go.mod h1:933PBGtQFJky3TEwYx4aEPZ4IxqhWh3R6DCmzqIn1hA= -k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.4.0 h1:lCJCxf/LIowc2IGS9TPjWDyXY4nOmdGdfcwwDQCOURQ= -k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= -k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf h1:EYm5AW/UUDbnmnI+gK0TJDVK9qPLhM+sRHYanNKw0EQ= -k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +k8s.io/api v0.21.3 h1:cblWILbLO8ar+Fj6xdDGr603HRsf8Wu9E9rngJeprZQ= +k8s.io/api v0.21.3/go.mod h1:hUgeYHUbBp23Ue4qdX9tR8/ANi/g3ehylAqDn9NWVOg= +k8s.io/apiextensions-apiserver v0.21.3 h1:+B6biyUWpqt41kz5x6peIsljlsuwvNAp/oFax/j2/aY= +k8s.io/apiextensions-apiserver v0.21.3/go.mod h1:kl6dap3Gd45+21Jnh6utCx8Z2xxLm8LGDkprcd+KbsE= +k8s.io/apimachinery v0.21.3 h1:3Ju4nvjCngxxMYby0BimUk+pQHPOQp3eCGChk5kfVII= +k8s.io/apimachinery v0.21.3/go.mod h1:H/IM+5vH9kZRNJ4l3x/fXP/5bOPJaVP/guptnZPeCFI= +k8s.io/apiserver v0.21.3/go.mod h1:eDPWlZG6/cCCMj/JBcEpDoK+I+6i3r9GsChYBHSbAzU= +k8s.io/client-go v0.21.3 h1:J9nxZTOmvkInRDCzcSNQmPJbDYN/PjlxXT9Mos3HcLg= +k8s.io/client-go v0.21.3/go.mod h1:+VPhCgTsaFmGILxR/7E1N0S+ryO010QBeNCv5JwRGYU= +k8s.io/code-generator v0.21.3/go.mod h1:K3y0Bv9Cz2cOW2vXUrNZlFbflhuPvuadW6JdnN6gGKo= +k8s.io/component-base v0.21.3 h1:4WuuXY3Npa+iFfi2aDRiOz+anhNvRfye0859ZgfC5Og= +k8s.io/component-base v0.21.3/go.mod h1:kkuhtfEHeZM6LkX0saqSK8PbdO7A0HigUngmhhrwfGQ= +k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= +k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= +k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= +k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= +k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts= +k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec= +k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 h1:vEx13qjvaZ4yfObSSXW7BrMc/KQBBT/Jyee8XtLf4x0= +k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= -k8s.io/utils v0.0.0-20190801114015-581e00157fb1 h1:+ySTxfHnfzZb9ys375PXNlLhkJPLKgHajBU0N62BDvE= -k8s.io/utils v0.0.0-20190801114015-581e00157fb1/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= -modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw= -modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk= -modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k= -modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= -modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= -sigs.k8s.io/controller-runtime v0.4.0 h1:wATM6/m+3w8lj8FXNaO6Fs/rq/vqoOjO1Q116Z9NPsg= -sigs.k8s.io/controller-runtime v0.4.0/go.mod h1:ApC79lpY3PHW9xj/w9pj+lYkLgwAAUZwfXkME1Lajns= -sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= -sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA= -sigs.k8s.io/testing_frameworks v0.1.2 h1:vK0+tvjF0BZ/RYFeZ1E6BYBwHJJXhjuZ3TdsEKH+UQM= -sigs.k8s.io/testing_frameworks v0.1.2/go.mod h1:ToQrwSC3s8Xf/lADdZp3Mktcql9CG0UAmdJG9th5i0w= -sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= +k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471 h1:DnzUXII7sVg1FJ/4JX6YDRJfLNAC7idRatPwe07suiI= +k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.19/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= +sigs.k8s.io/controller-runtime v0.9.6 h1:EevVMlgUj4fC1NVM4+DB3iPkWkmGRNarA66neqv9Qew= +sigs.k8s.io/controller-runtime v0.9.6/go.mod h1:q6PpkM5vqQubEKUKOM6qr06oXGzOBcCby1DA9FbyZeA= +sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno= +sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= +sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q= +sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/handlers/message_queue.go b/handlers/message_queue.go index b5f93141..1c79351b 100644 --- a/handlers/message_queue.go +++ b/handlers/message_queue.go @@ -474,7 +474,7 @@ func (h *Messaging) GetPendingMessages() { }, "statusMessages": nil, }) - if err := h.Client.Patch(ctx, &build, client.ConstantPatch(types.MergePatchType, mergePatch)); err != nil { + if err := h.Client.Patch(ctx, &build, client.RawPatch(types.MergePatchType, mergePatch)); err != nil { opLog.Error(err, fmt.Sprintf("Unable to update status condition")) break } From 74b23e3caae19f551b91a82cc29a3375091df950 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Thu, 28 Oct 2021 17:16:07 +1100 Subject: [PATCH 31/35] fix: update action dependencies --- .github/workflows/lagoon-kbd.yaml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/lagoon-kbd.yaml b/.github/workflows/lagoon-kbd.yaml index 058a5260..7ed05976 100644 --- a/.github/workflows/lagoon-kbd.yaml +++ b/.github/workflows/lagoon-kbd.yaml @@ -18,22 +18,22 @@ jobs: fetch-depth: "0" - name: Set up testing dependencies run: sudo apt-get update && sudo apt-get -y install build-essential && sudo apt-get clean - - name: Install go, kustomize, kubebuilder, helm, docker-compose, kind + - name: Setup correct Go version + uses: actions/setup-go@v2 + with: + go-version: '1.16' + - name: Install kustomize, kubebuilder, helm, docker-compose, kind run: | - #go - sudo rm -rf /usr/local/go - curl -sLo /tmp/go1.13.7.linux-amd64.tar.gz https://dl.google.com/go/go1.13.7.linux-amd64.tar.gz - sudo tar -C /usr/local -xzf /tmp/go1.13.7.linux-amd64.tar.gz #kustomize curl -sLo /tmp/kustomize_v3.5.4_linux_amd64.tar.gz https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv3.5.4/kustomize_v3.5.4_linux_amd64.tar.gz sudo tar -C /usr/local/bin -xzf /tmp/kustomize_v3.5.4_linux_amd64.tar.gz #kubebuilder - curl -sL https://github.com/kubernetes-sigs/kubebuilder/releases/download/v2.2.0/kubebuilder_2.2.0_linux_amd64.tar.gz | tar -xz -C /tmp/ + curl -sL https://github.com/kubernetes-sigs/kubebuilder/releases/download/v2.3.2/kubebuilder_2.3.2_linux_amd64.tar.gz | tar -xz -C /tmp/ sudo mkdir -p /usr/local/kubebuilder/bin - sudo mv /tmp/kubebuilder_2.2.0_linux_amd64/bin/* /usr/local/kubebuilder/bin + sudo mv /tmp/kubebuilder_2.3.2_linux_amd64/bin/* /usr/local/kubebuilder/bin chmod +x /usr/local/kubebuilder/bin/* #helm - curl -sL https://get.helm.sh/helm-v3.3.0-rc.1-linux-amd64.tar.gz | tar -xz -C /tmp/ + curl -sL https://get.helm.sh/helm-v3.6.3-linux-amd64.tar.gz | tar -xz -C /tmp/ sudo mv /tmp/linux-amd64/helm /usr/local/bin/helm chmod +x /usr/local/bin/helm #docker-compose From ca2fad9dfb850b927122f2dbc2b5fb237a9651e6 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 10 Nov 2021 15:59:20 +1100 Subject: [PATCH 32/35] fix: actually update lagoon when pending builds are cancelled --- controllers/helpers.go | 1 + controllers/lagoonbuild_controller.go | 9 ++++- controllers/lagoonbuild_helpers.go | 53 ++++++++++++++++++++++++--- 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/controllers/helpers.go b/controllers/helpers.go index fb5bfdb1..21d142b9 100644 --- a/controllers/helpers.go +++ b/controllers/helpers.go @@ -221,6 +221,7 @@ func cancelExtraBuilds(ctx context.Context, r client.Client, opLog logr.Logger, pendingBuild.Labels["lagoon.sh/buildStatus"] = status } else { // cancel any other pending builds + opLog.Info(fmt.Sprintf("Setting build %s as cancelled", pendingBuild.ObjectMeta.Name)) pendingBuild.Labels["lagoon.sh/buildStatus"] = string(lagoonv1alpha1.BuildStatusCancelled) } if err := r.Update(ctx, pendingBuild); err != nil { diff --git a/controllers/lagoonbuild_controller.go b/controllers/lagoonbuild_controller.go index 4f3f76ad..0d4a554b 100644 --- a/controllers/lagoonbuild_controller.go +++ b/controllers/lagoonbuild_controller.go @@ -93,6 +93,14 @@ func (r *LagoonBuildReconciler) Reconcile(ctx context.Context, req ctrl.Request) // examine DeletionTimestamp to determine if object is under deletion if lagoonBuild.ObjectMeta.DeletionTimestamp.IsZero() { + // if the build isn't being deleted, but the status is cancelled + // then clean up the undeployable build + if value, ok := lagoonBuild.ObjectMeta.Labels["lagoon.sh/buildStatus"]; ok { + if value == string(lagoonv1alpha1.BuildStatusCancelled) { + opLog.Info(fmt.Sprintf("Cleaning up build %s as cancelled", lagoonBuild.ObjectMeta.Name)) + r.cleanUpUndeployableBuild(ctx, lagoonBuild, "This build was cancelled, as a new one was deployed before this one could start.", opLog) + } + } if r.LFFQoSEnabled { // handle QoS builds here // if we do have a `lagoon.sh/buildStatus` set as running, then process it @@ -209,7 +217,6 @@ func (r *LagoonBuildReconciler) createNamespaceBuild(ctx context.Context, // so end this reconcile process pendingBuilds := &lagoonv1alpha1.LagoonBuildList{} return ctrl.Result{}, cancelExtraBuilds(ctx, r.Client, opLog, pendingBuilds, namespace.ObjectMeta.Name, string(lagoonv1alpha1.BuildStatusPending)) - // return ctrl.Result{}, nil } // getOrCreateBuildResource will deepcopy the lagoon build into a new resource and push it to the new namespace diff --git a/controllers/lagoonbuild_helpers.go b/controllers/lagoonbuild_helpers.go index 6f5d490d..4fefd45f 100644 --- a/controllers/lagoonbuild_helpers.go +++ b/controllers/lagoonbuild_helpers.go @@ -6,6 +6,7 @@ import ( "encoding/json" "fmt" "regexp" + "sort" "strconv" "strings" "time" @@ -163,7 +164,8 @@ func (r *LagoonBuildReconciler) getOrCreateNamespace(ctx context.Context, namesp } } if namespace.Status.Phase == corev1.NamespaceTerminating { - r.cleanUpTerminatingNamespaceBuild(ctx, namespace, lagoonBuild, opLog) + opLog.Info(fmt.Sprintf("Cleaning up build %s as cancelled, the namespace is stuck in terminating state", lagoonBuild.ObjectMeta.Name)) + r.cleanUpUndeployableBuild(ctx, lagoonBuild, "Namespace is currently in terminating status - contact your Lagoon support team for help", opLog) return fmt.Errorf("%s is currently terminating, aborting build", ns) } @@ -906,11 +908,11 @@ func (r *LagoonBuildReconciler) processBuild(ctx context.Context, opLog logr.Log return nil } -// cleanUpTerminatingNamespaceBuild will clean up a build if the namespace is being terminated. -func (r *LagoonBuildReconciler) cleanUpTerminatingNamespaceBuild( +// cleanUpUndeployableBuild will clean up a build if the namespace is being terminated, or some other reason that it can't deploy (or create the pod) +func (r *LagoonBuildReconciler) cleanUpUndeployableBuild( ctx context.Context, - namespace *corev1.Namespace, lagoonBuild lagoonv1alpha1.LagoonBuild, + message string, opLog logr.Logger, ) error { var allContainerLogs []byte @@ -920,7 +922,7 @@ func (r *LagoonBuildReconciler) cleanUpTerminatingNamespaceBuild( ======================================== Build cancelled ======================================== -Namespace is currently in terminating status - contact your Lagoon support team for help`)) +%s`, message)) var jobCondition lagoonv1alpha1.BuildStatusType jobCondition = lagoonv1alpha1.BuildStatusCancelled lagoonBuild.Labels["lagoon.sh/buildStatus"] = string(jobCondition) @@ -959,3 +961,44 @@ Namespace is currently in terminating status - contact your Lagoon support team } return nil } + +func (r *LagoonBuildReconciler) cancelExtraBuilds(ctx context.Context, opLog logr.Logger, pendingBuilds *lagoonv1alpha1.LagoonBuildList, ns string, status string) error { + listOption := (&client.ListOptions{}).ApplyOptions([]client.ListOption{ + client.InNamespace(ns), + client.MatchingLabels(map[string]string{"lagoon.sh/buildStatus": string(lagoonv1alpha1.BuildStatusPending)}), + }) + if err := r.List(ctx, pendingBuilds, listOption); err != nil { + return fmt.Errorf("Unable to list builds in the namespace, there may be none or something went wrong: %v", err) + } + opLog.Info(fmt.Sprintf("There are %v Pending builds", len(pendingBuilds.Items))) + // if we have any pending builds, then grab the latest one and make it running + // if there are any other pending builds, cancel them so only the latest one runs + sort.Slice(pendingBuilds.Items, func(i, j int) bool { + return pendingBuilds.Items[i].ObjectMeta.CreationTimestamp.After(pendingBuilds.Items[j].ObjectMeta.CreationTimestamp.Time) + }) + if len(pendingBuilds.Items) > 0 { + for idx, pBuild := range pendingBuilds.Items { + pendingBuild := pBuild.DeepCopy() + if idx == 0 { + pendingBuild.Labels["lagoon.sh/buildStatus"] = status + } else { + // cancel any other pending builds + opLog.Info(fmt.Sprintf("Attempting to cancel build %s", pendingBuild.ObjectMeta.Name)) + pendingBuild.Labels["lagoon.sh/buildStatus"] = string(lagoonv1alpha1.BuildStatusCancelled) + } + if err := r.Update(ctx, pendingBuild); err != nil { + return err + } + var lagoonBuild lagoonv1alpha1.LagoonBuild + if err := r.Get(ctx, types.NamespacedName{ + Namespace: pendingBuild.ObjectMeta.Namespace, + Name: pendingBuild.ObjectMeta.Name, + }, &lagoonBuild); err != nil { + return ignoreNotFound(err) + } + opLog.Info(fmt.Sprintf("Cleaning up build %s as cancelled", lagoonBuild.ObjectMeta.Name)) + r.cleanUpUndeployableBuild(ctx, lagoonBuild, "This build was cancelled, as a new one was deployed before this one could start.", opLog) + } + } + return nil +} From c703a666ffd00cbfcfdb135ae306db3349ce72ca Mon Sep 17 00:00:00 2001 From: Toby Bellwood Date: Wed, 22 Dec 2021 10:36:52 +1100 Subject: [PATCH 33/35] initial re-namespace --- .../workflows/{lagoon-kbd.yaml => remote-controller.yaml} | 3 ++- PROJECT | 2 +- README.md | 6 +++--- api/v1alpha1/zz_generated.deepcopy.go | 1 + build-push.sh | 4 ++-- config/default/kustomization.yaml | 4 ++-- config/manager/kustomization.yaml | 2 +- controller-test.sh | 6 +++--- controllers/helpers.go | 2 +- controllers/lagoon_harborintegration.go | 2 +- controllers/lagoonbuild_controller.go | 4 ++-- controllers/lagoonbuild_deletionhandlers.go | 2 +- controllers/lagoonbuild_helpers.go | 2 +- controllers/lagoonbuild_qoshandler.go | 2 +- controllers/lagoonbuild_standardhandler.go | 2 +- controllers/lagoonmonitor_buildhandlers.go | 2 +- controllers/lagoonmonitor_controller.go | 4 ++-- controllers/lagoonmonitor_taskhandlers.go | 2 +- controllers/lagoontask_controller.go | 2 +- controllers/suite_test.go | 2 +- go.mod | 2 +- handlers/helpers.go | 2 +- handlers/message_queue.go | 2 +- handlers/misctask_handler.go | 2 +- handlers/resource_cleanup.go | 2 +- helm-update.sh | 2 +- main.go | 6 +++--- test-resources/example-project1.yaml | 2 +- test-resources/example-project2.yaml | 2 +- 29 files changed, 40 insertions(+), 38 deletions(-) rename .github/workflows/{lagoon-kbd.yaml => remote-controller.yaml} (97%) diff --git a/.github/workflows/lagoon-kbd.yaml b/.github/workflows/remote-controller.yaml similarity index 97% rename from .github/workflows/lagoon-kbd.yaml rename to .github/workflows/remote-controller.yaml index 7ed05976..16c4e78d 100644 --- a/.github/workflows/lagoon-kbd.yaml +++ b/.github/workflows/remote-controller.yaml @@ -1,9 +1,10 @@ -name: Lagoon KBD Test +name: Lagoon Remote Controller Test on: push: branches: - main + - re-namespace pull_request: branches: - main diff --git a/PROJECT b/PROJECT index 93a5a472..fa156a65 100644 --- a/PROJECT +++ b/PROJECT @@ -1,5 +1,5 @@ domain: amazee.io -repo: github.com/amazeeio/lagoon-kbd +repo: github.com/uselagoon/remote-controller resources: - group: lagoon kind: LagoonBuild diff --git a/README.md b/README.md index f8f99122..a5f00e9d 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ There is currently no documentation for how to do this, we may release more info Using [Helm 3](https://helm.sh/docs/intro/install/) ``` -helm repo add lagoon-builddeploy https://raw.githubusercontent.com/amazeeio/lagoon-kbd/main/charts +helm repo add lagoon-builddeploy https://raw.githubusercontent.com/uselagoon/remote-controller/main/charts ## with rabbitmq support for communicating with a lagoon messaging queue helm upgrade --install -n lagoon-builddeploy lagoon-builddeploy lagoon-builddeploy/lagoon-builddeploy \ @@ -49,7 +49,7 @@ You will need to install any prerequisites for kubebuilder [see here](https://bo # install any requirements make install # deploy the actual handler -make IMG=amazeeio/lagoon-builddeploy:latest deploy +make IMG=uselagoon/remote-controller:latest deploy ``` ## LagoonBuild Spec @@ -62,7 +62,7 @@ metadata: spec: build: ci: 'false' # this is a string, not a bool - image: amazeeio/kubectl-build-deploy-dind:v1.8.1 + image: uselagoon/kubectl-build-deploy-dind:v1.8.1 type: branch gitReference: origin/main openshift: false diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index df53ce5b..c3f4edfd 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1,3 +1,4 @@ +//go:build !ignore_autogenerated // +build !ignore_autogenerated /* diff --git a/build-push.sh b/build-push.sh index d0890bc2..14230670 100755 --- a/build-push.sh +++ b/build-push.sh @@ -1,6 +1,6 @@ #!/bin/bash -REPO=${2:-amazeeio} +REPO=${2:-uselagoon} TAG=${1:-latest} -IMGNAME=${3:-lagoon-builddeploy} +IMGNAME=${3:-remote-controller} echo "Creating image for $REPO/${IMGNAME}:$TAG and pushing to docker hub" make IMG=$REPO/${IMGNAME}:$TAG docker-build && make IMG=$REPO/${IMGNAME}:$TAG docker-push diff --git a/config/default/kustomization.yaml b/config/default/kustomization.yaml index 1c32b936..d22ccc90 100644 --- a/config/default/kustomization.yaml +++ b/config/default/kustomization.yaml @@ -1,12 +1,12 @@ # Adds namespace to all resources. -namespace: lagoon-kbd-system +namespace: remote-controller-system # Value of this field is prepended to the # names of all resources, e.g. a deployment named # "wordpress" becomes "alices-wordpress". # Note that it should also match with the prefix (text before '-') of the namespace # field above. -namePrefix: lagoon-kbd- +namePrefix: remote-controller- # Labels to add to all resources and selectors. #commonLabels: diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index 6f0d463d..66e873ab 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -4,5 +4,5 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization images: - name: controller - newName: amazeeio/lagoon-builddeploy + newName: uselagoon/remote-controller newTag: test-tag diff --git a/controller-test.sh b/controller-test.sh index 7c67a631..52894674 100755 --- a/controller-test.sh +++ b/controller-test.sh @@ -8,10 +8,10 @@ KIND_VER=v1.17.5 # or get the latest tagged version of a specific k8s version of kind #KIND_VER=$(curl -s https://hub.docker.com/v2/repositories/kindest/node/tags | jq -r '.results | .[].name' | grep 'v1.17' | sort -Vr | head -1) KIND_NAME=chart-testing -CONTROLLER_IMAGE=amazeeio/lagoon-builddeploy:test-tag +CONTROLLER_IMAGE=uselagoon/remote-controller:test-tag -CONTROLLER_NAMESPACE=lagoon-kbd-system +CONTROLLER_NAMESPACE=remote-controller-system CHECK_TIMEOUT=20 NS=drupal-example-install @@ -238,7 +238,7 @@ echo ' \"spec\": { \"build\": { \"ci\": \"true\", - \"image\": \"amazeeio\/kubectl-build-deploy-dind:latest\", + \"image\": \"uselagoon\/kubectl-build-deploy-dind:latest\", \"type\": \"branch\" }, \"gitReference\": \"origin\/install\", diff --git a/controllers/helpers.go b/controllers/helpers.go index fb5bfdb1..45b99e65 100644 --- a/controllers/helpers.go +++ b/controllers/helpers.go @@ -13,8 +13,8 @@ import ( "strings" "time" - lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" "github.com/go-logr/logr" + lagoonv1alpha1 "github.com/uselagoon/remote-controller/api/v1alpha1" apierrors "k8s.io/apimachinery/pkg/api/errors" "sigs.k8s.io/controller-runtime/pkg/client" ) diff --git a/controllers/lagoon_harborintegration.go b/controllers/lagoon_harborintegration.go index a170ff4d..f35e7512 100644 --- a/controllers/lagoon_harborintegration.go +++ b/controllers/lagoon_harborintegration.go @@ -9,11 +9,11 @@ import ( "encoding/json" "time" - lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" "github.com/go-logr/logr" harborv2 "github.com/mittwald/goharbor-client/v3/apiv2" "github.com/mittwald/goharbor-client/v3/apiv2/model" "github.com/mittwald/goharbor-client/v3/apiv2/model/legacy" + lagoonv1alpha1 "github.com/uselagoon/remote-controller/api/v1alpha1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/controllers/lagoonbuild_controller.go b/controllers/lagoonbuild_controller.go index 4f3f76ad..2a35ec71 100644 --- a/controllers/lagoonbuild_controller.go +++ b/controllers/lagoonbuild_controller.go @@ -28,8 +28,8 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" - "github.com/amazeeio/lagoon-kbd/handlers" + lagoonv1alpha1 "github.com/uselagoon/remote-controller/api/v1alpha1" + "github.com/uselagoon/remote-controller/handlers" // Openshift ) diff --git a/controllers/lagoonbuild_deletionhandlers.go b/controllers/lagoonbuild_deletionhandlers.go index 48c97317..99b63024 100644 --- a/controllers/lagoonbuild_deletionhandlers.go +++ b/controllers/lagoonbuild_deletionhandlers.go @@ -10,8 +10,8 @@ import ( "strings" "time" - lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" "github.com/go-logr/logr" + lagoonv1alpha1 "github.com/uselagoon/remote-controller/api/v1alpha1" "gopkg.in/matryer/try.v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/labels" diff --git a/controllers/lagoonbuild_helpers.go b/controllers/lagoonbuild_helpers.go index 6f5d490d..a21433cf 100644 --- a/controllers/lagoonbuild_helpers.go +++ b/controllers/lagoonbuild_helpers.go @@ -17,8 +17,8 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" - lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" "github.com/go-logr/logr" + lagoonv1alpha1 "github.com/uselagoon/remote-controller/api/v1alpha1" // Openshift projectv1 "github.com/openshift/api/project/v1" diff --git a/controllers/lagoonbuild_qoshandler.go b/controllers/lagoonbuild_qoshandler.go index 670144e3..60fa3ab5 100644 --- a/controllers/lagoonbuild_qoshandler.go +++ b/controllers/lagoonbuild_qoshandler.go @@ -6,8 +6,8 @@ import ( "fmt" "sort" - lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" "github.com/go-logr/logr" + lagoonv1alpha1 "github.com/uselagoon/remote-controller/api/v1alpha1" "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" diff --git a/controllers/lagoonbuild_standardhandler.go b/controllers/lagoonbuild_standardhandler.go index edda172a..a97b5746 100644 --- a/controllers/lagoonbuild_standardhandler.go +++ b/controllers/lagoonbuild_standardhandler.go @@ -5,8 +5,8 @@ import ( "encoding/json" "fmt" - lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" "github.com/go-logr/logr" + lagoonv1alpha1 "github.com/uselagoon/remote-controller/api/v1alpha1" "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" diff --git a/controllers/lagoonmonitor_buildhandlers.go b/controllers/lagoonmonitor_buildhandlers.go index 01a81ab6..52856418 100644 --- a/controllers/lagoonmonitor_buildhandlers.go +++ b/controllers/lagoonmonitor_buildhandlers.go @@ -10,8 +10,8 @@ import ( "strings" "time" - lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" "github.com/go-logr/logr" + lagoonv1alpha1 "github.com/uselagoon/remote-controller/api/v1alpha1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" diff --git a/controllers/lagoonmonitor_controller.go b/controllers/lagoonmonitor_controller.go index 980a9a4d..9f24f88d 100644 --- a/controllers/lagoonmonitor_controller.go +++ b/controllers/lagoonmonitor_controller.go @@ -21,9 +21,9 @@ import ( "fmt" "io" - lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" - "github.com/amazeeio/lagoon-kbd/handlers" "github.com/go-logr/logr" + lagoonv1alpha1 "github.com/uselagoon/remote-controller/api/v1alpha1" + "github.com/uselagoon/remote-controller/handlers" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" diff --git a/controllers/lagoonmonitor_taskhandlers.go b/controllers/lagoonmonitor_taskhandlers.go index e5a92a1e..953b8859 100644 --- a/controllers/lagoonmonitor_taskhandlers.go +++ b/controllers/lagoonmonitor_taskhandlers.go @@ -8,8 +8,8 @@ import ( "fmt" "time" - lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" "github.com/go-logr/logr" + lagoonv1alpha1 "github.com/uselagoon/remote-controller/api/v1alpha1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" diff --git a/controllers/lagoontask_controller.go b/controllers/lagoontask_controller.go index cad63777..2144b917 100644 --- a/controllers/lagoontask_controller.go +++ b/controllers/lagoontask_controller.go @@ -31,7 +31,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" + lagoonv1alpha1 "github.com/uselagoon/remote-controller/api/v1alpha1" // openshift oappsv1 "github.com/openshift/api/apps/v1" ) diff --git a/controllers/suite_test.go b/controllers/suite_test.go index 0ccac2c9..58528078 100644 --- a/controllers/suite_test.go +++ b/controllers/suite_test.go @@ -22,7 +22,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" + lagoonv1alpha1 "github.com/uselagoon/remote-controller/api/v1alpha1" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/client" diff --git a/go.mod b/go.mod index efb2ace1..9e326c89 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/amazeeio/lagoon-kbd +module github.com/uselagoon/remote-controller go 1.16 diff --git a/handlers/helpers.go b/handlers/helpers.go index 6caba1e4..b64bfeec 100644 --- a/handlers/helpers.go +++ b/handlers/helpers.go @@ -11,7 +11,7 @@ import ( "strings" "time" - lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" + lagoonv1alpha1 "github.com/uselagoon/remote-controller/api/v1alpha1" apierrors "k8s.io/apimachinery/pkg/api/errors" ) diff --git a/handlers/message_queue.go b/handlers/message_queue.go index 1c79351b..a58dc60a 100644 --- a/handlers/message_queue.go +++ b/handlers/message_queue.go @@ -8,8 +8,8 @@ import ( "strings" "time" - lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" "github.com/cheshir/go-mq" + lagoonv1alpha1 "github.com/uselagoon/remote-controller/api/v1alpha1" "gopkg.in/matryer/try.v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" diff --git a/handlers/misctask_handler.go b/handlers/misctask_handler.go index fc5bb9f5..8a948ed3 100644 --- a/handlers/misctask_handler.go +++ b/handlers/misctask_handler.go @@ -6,8 +6,8 @@ import ( "fmt" "time" - lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" "github.com/go-logr/logr" + lagoonv1alpha1 "github.com/uselagoon/remote-controller/api/v1alpha1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" diff --git a/handlers/resource_cleanup.go b/handlers/resource_cleanup.go index c922e944..e195eafb 100644 --- a/handlers/resource_cleanup.go +++ b/handlers/resource_cleanup.go @@ -11,7 +11,7 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" + lagoonv1alpha1 "github.com/uselagoon/remote-controller/api/v1alpha1" ) type cleanup interface { diff --git a/helm-update.sh b/helm-update.sh index 12c59493..01485fd2 100755 --- a/helm-update.sh +++ b/helm-update.sh @@ -29,7 +29,7 @@ case $1 in helm delete -n lagoon-builddeploy lagoon-builddeploy ;; install) - helm repo add lagoon-builddeploy https://raw.githubusercontent.com/amazeeio/lagoon-kbd/main/charts + helm repo add lagoon-builddeploy https://raw.githubusercontent.com/uselagoon/remote-controller/main/charts helm upgrade --install -n lagoon-builddeploy lagoon-builddeploy lagoon-builddeploy/lagoon-builddeploy ;; install-tgz) diff --git a/main.go b/main.go index fcc15fd9..a67365dc 100644 --- a/main.go +++ b/main.go @@ -25,10 +25,10 @@ import ( "strings" "time" - lagoonv1alpha1 "github.com/amazeeio/lagoon-kbd/api/v1alpha1" - "github.com/amazeeio/lagoon-kbd/controllers" - "github.com/amazeeio/lagoon-kbd/handlers" "github.com/cheshir/go-mq" + lagoonv1alpha1 "github.com/uselagoon/remote-controller/api/v1alpha1" + "github.com/uselagoon/remote-controller/controllers" + "github.com/uselagoon/remote-controller/handlers" str2duration "github.com/xhit/go-str2duration/v2" "k8s.io/apimachinery/pkg/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" diff --git a/test-resources/example-project1.yaml b/test-resources/example-project1.yaml index 5de349ef..38cc628a 100644 --- a/test-resources/example-project1.yaml +++ b/test-resources/example-project1.yaml @@ -5,7 +5,7 @@ metadata: spec: build: ci: 'true' #to make sure that readwritemany is changed to readwriteonce - image: amazeeio/kubectl-build-deploy-dind:latest + image: uselagoon/kubectl-build-deploy-dind:latest type: branch gitReference: origin/install project: diff --git a/test-resources/example-project2.yaml b/test-resources/example-project2.yaml index 39bfcaa7..b74cdbbe 100644 --- a/test-resources/example-project2.yaml +++ b/test-resources/example-project2.yaml @@ -5,7 +5,7 @@ metadata: spec: build: ci: 'true' #to make sure that readwritemany is changed to readwriteonce - image: amazeeio/kubectl-build-deploy-dind:latest + image: uselagoon/kubectl-build-deploy-dind:latest type: branch gitReference: origin/install project: From 11c2c86212fa0105d3cf5e28c427078c94becd69 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 22 Dec 2021 12:42:51 +1100 Subject: [PATCH 34/35] chore: update log messaging --- controllers/lagoonbuild_controller.go | 2 +- controllers/lagoonbuild_helpers.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/controllers/lagoonbuild_controller.go b/controllers/lagoonbuild_controller.go index 0d4a554b..a974df83 100644 --- a/controllers/lagoonbuild_controller.go +++ b/controllers/lagoonbuild_controller.go @@ -98,7 +98,7 @@ func (r *LagoonBuildReconciler) Reconcile(ctx context.Context, req ctrl.Request) if value, ok := lagoonBuild.ObjectMeta.Labels["lagoon.sh/buildStatus"]; ok { if value == string(lagoonv1alpha1.BuildStatusCancelled) { opLog.Info(fmt.Sprintf("Cleaning up build %s as cancelled", lagoonBuild.ObjectMeta.Name)) - r.cleanUpUndeployableBuild(ctx, lagoonBuild, "This build was cancelled, as a new one was deployed before this one could start.", opLog) + r.cleanUpUndeployableBuild(ctx, lagoonBuild, "This build was cancelled as a newer build was triggered.", opLog) } } if r.LFFQoSEnabled { diff --git a/controllers/lagoonbuild_helpers.go b/controllers/lagoonbuild_helpers.go index 4fefd45f..aa6297ad 100644 --- a/controllers/lagoonbuild_helpers.go +++ b/controllers/lagoonbuild_helpers.go @@ -997,7 +997,7 @@ func (r *LagoonBuildReconciler) cancelExtraBuilds(ctx context.Context, opLog log return ignoreNotFound(err) } opLog.Info(fmt.Sprintf("Cleaning up build %s as cancelled", lagoonBuild.ObjectMeta.Name)) - r.cleanUpUndeployableBuild(ctx, lagoonBuild, "This build was cancelled, as a new one was deployed before this one could start.", opLog) + r.cleanUpUndeployableBuild(ctx, lagoonBuild, "This build was cancelled as a newer build was triggered.", opLog) } } return nil From a4c761515d9e856ac29f26129f99255a156bebe7 Mon Sep 17 00:00:00 2001 From: Ben Jackson Date: Wed, 22 Dec 2021 19:20:15 +1100 Subject: [PATCH 35/35] feat: add cluster to log meta --- api/v1alpha1/lagoonmessaging_types.go | 1 + controllers/lagoonbuild_controller.go | 1 + controllers/lagoonbuild_deletionhandlers.go | 3 +++ controllers/lagoonmonitor_buildhandlers.go | 3 +++ controllers/lagoonmonitor_controller.go | 1 + controllers/lagoonmonitor_taskhandlers.go | 3 +++ controllers/lagoontask_controller.go | 1 + main.go | 5 ++++- 8 files changed, 17 insertions(+), 1 deletion(-) diff --git a/api/v1alpha1/lagoonmessaging_types.go b/api/v1alpha1/lagoonmessaging_types.go index 2bec26ed..ae8e1aed 100644 --- a/api/v1alpha1/lagoonmessaging_types.go +++ b/api/v1alpha1/lagoonmessaging_types.go @@ -36,6 +36,7 @@ type LagoonLogMeta struct { Task *LagoonTaskInfo `json:"task,omitempty"` Key string `json:"key,omitempty"` AdvancedData string `json:"advancedData,omitempty"` + Cluster string `json:"clusterName,omitempty"` } // LagoonMessage is used for sending build info back to Lagoon diff --git a/controllers/lagoonbuild_controller.go b/controllers/lagoonbuild_controller.go index 6918ae1c..a8e0432f 100644 --- a/controllers/lagoonbuild_controller.go +++ b/controllers/lagoonbuild_controller.go @@ -71,6 +71,7 @@ type LagoonBuildReconciler struct { LFFQoSEnabled bool BuildQoS BuildQoS NativeCronPodMinFrequency int + LagoonTargetName string } // +kubebuilder:rbac:groups=lagoon.amazee.io,resources=lagoonbuilds,verbs=get;list;watch;create;update;patch;delete diff --git a/controllers/lagoonbuild_deletionhandlers.go b/controllers/lagoonbuild_deletionhandlers.go index 99b63024..f372bef0 100644 --- a/controllers/lagoonbuild_deletionhandlers.go +++ b/controllers/lagoonbuild_deletionhandlers.go @@ -239,6 +239,7 @@ func (r *LagoonBuildReconciler) cancelledBuildLogsToLagoonLogs(ctx context.Conte BuildPhase: condition, RemoteID: string(lagoonBuild.ObjectMeta.UID), LogLink: lagoonBuild.Spec.Project.UILink, + Cluster: r.LagoonTargetName, }, } // add the actual build log message @@ -285,6 +286,7 @@ func (r *LagoonBuildReconciler) updateCancelledDeploymentAndEnvironmentTask(ctx BuildName: lagoonBuild.ObjectMeta.Name, LogLink: lagoonBuild.Spec.Project.UILink, RemoteID: string(lagoonBuild.ObjectMeta.UID), + Cluster: r.LagoonTargetName, }, } labelRequirements1, _ := labels.NewRequirement("lagoon.sh/service", selection.NotIn, []string{"faketest"}) @@ -366,6 +368,7 @@ func (r *LagoonBuildReconciler) cancelledBuildStatusLogsToLagoonLogs(ctx context BuildPhase: condition, BuildName: lagoonBuild.ObjectMeta.Name, LogLink: lagoonBuild.Spec.Project.UILink, + Cluster: r.LagoonTargetName, }, Message: fmt.Sprintf("*[%s]* %s Build `%s` %s", lagoonBuild.Spec.Project.Name, diff --git a/controllers/lagoonmonitor_buildhandlers.go b/controllers/lagoonmonitor_buildhandlers.go index 52856418..2dc0349f 100644 --- a/controllers/lagoonmonitor_buildhandlers.go +++ b/controllers/lagoonmonitor_buildhandlers.go @@ -174,6 +174,7 @@ func (r *LagoonMonitorReconciler) buildLogsToLagoonLogs(ctx context.Context, BuildPhase: condition, RemoteID: string(jobPod.ObjectMeta.UID), LogLink: lagoonBuild.Spec.Project.UILink, + Cluster: r.LagoonTargetName, }, } // add the actual build log message @@ -233,6 +234,7 @@ func (r *LagoonMonitorReconciler) updateDeploymentAndEnvironmentTask(ctx context BuildName: lagoonBuild.ObjectMeta.Name, LogLink: lagoonBuild.Spec.Project.UILink, RemoteID: string(jobPod.ObjectMeta.UID), + Cluster: r.LagoonTargetName, }, } labelRequirements1, _ := labels.NewRequirement("lagoon.sh/service", selection.NotIn, []string{"faketest"}) @@ -340,6 +342,7 @@ func (r *LagoonMonitorReconciler) buildStatusLogsToLagoonLogs(ctx context.Contex BuildPhase: condition, BuildName: lagoonBuild.ObjectMeta.Name, LogLink: lagoonBuild.Spec.Project.UILink, + Cluster: r.LagoonTargetName, }, } // if we aren't being provided the lagoon config, we can skip adding the routes etc diff --git a/controllers/lagoonmonitor_controller.go b/controllers/lagoonmonitor_controller.go index 9f24f88d..3872fd30 100644 --- a/controllers/lagoonmonitor_controller.go +++ b/controllers/lagoonmonitor_controller.go @@ -42,6 +42,7 @@ type LagoonMonitorReconciler struct { Messaging *handlers.Messaging ControllerNamespace string EnableDebug bool + LagoonTargetName string } // slice of the different failure states of pods that we care about diff --git a/controllers/lagoonmonitor_taskhandlers.go b/controllers/lagoonmonitor_taskhandlers.go index 953b8859..1002142e 100644 --- a/controllers/lagoonmonitor_taskhandlers.go +++ b/controllers/lagoonmonitor_taskhandlers.go @@ -156,6 +156,7 @@ func (r *LagoonMonitorReconciler) taskLogsToLagoonLogs(opLog logr.Logger, JobStatus: condition, RemoteID: string(jobPod.ObjectMeta.UID), Key: lagoonTask.Spec.Key, + Cluster: r.LagoonTargetName, }, Message: fmt.Sprintf(`======================================== Logs on pod %s @@ -208,6 +209,7 @@ func (r *LagoonMonitorReconciler) updateLagoonTask(opLog logr.Logger, JobStatus: condition, RemoteID: string(jobPod.ObjectMeta.UID), Key: lagoonTask.Spec.Key, + Cluster: r.LagoonTargetName, }, } if _, ok := jobPod.ObjectMeta.Annotations["lagoon.sh/taskData"]; ok { @@ -272,6 +274,7 @@ func (r *LagoonMonitorReconciler) taskStatusLogsToLagoonLogs(opLog logr.Logger, JobStatus: condition, RemoteID: string(jobPod.ObjectMeta.UID), Key: lagoonTask.Spec.Key, + Cluster: r.LagoonTargetName, }, Message: fmt.Sprintf("*[%s]* Task `%s` *%s* %s", lagoonTask.Spec.Project.Name, diff --git a/controllers/lagoontask_controller.go b/controllers/lagoontask_controller.go index 2144b917..05433d67 100644 --- a/controllers/lagoontask_controller.go +++ b/controllers/lagoontask_controller.go @@ -45,6 +45,7 @@ type LagoonTaskReconciler struct { ControllerNamespace string TaskSettings LagoonTaskSettings EnableDebug bool + LagoonTargetName string } // LagoonTaskSettings is for the settings for task API/SSH host/ports diff --git a/main.go b/main.go index a67365dc..d3c7df38 100644 --- a/main.go +++ b/main.go @@ -621,6 +621,7 @@ func main() { LFFQoSEnabled: lffQoSEnabled, BuildQoS: buildQoSConfig, NativeCronPodMinFrequency: nativeCronPodMinFrequency, + LagoonTargetName: lagoonTargetName, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "LagoonBuild") os.Exit(1) @@ -633,6 +634,7 @@ func main() { Messaging: messaging, ControllerNamespace: controllerNamespace, EnableDebug: enableDebug, + LagoonTargetName: lagoonTargetName, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "LagoonMonitor") os.Exit(1) @@ -648,7 +650,8 @@ func main() { SSHHost: lagoonSSHHost, SSHPort: lagoonSSHPort, }, - EnableDebug: enableDebug, + EnableDebug: enableDebug, + LagoonTargetName: lagoonTargetName, }).SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "LagoonTask") os.Exit(1)