diff --git a/deployment/helm/templates/core/task-crd.yml b/deployment/helm/templates/core/task-crd.yml index db7fdf2ad..f739d3b1d 100644 --- a/deployment/helm/templates/core/task-crd.yml +++ b/deployment/helm/templates/core/task-crd.yml @@ -174,6 +174,18 @@ spec: type: array image: type: string + imagePullSecrets: + items: + description: LocalObjectReference contains enough information to + let you locate the referenced object inside the same namespace. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + type: array memoryMB: format: int64 type: integer @@ -183,13 +195,6 @@ spec: type: string orgName: type: string - privateRegistry: - properties: - password: - type: string - username: - type: string - type: object spaceGUID: type: string spaceName: diff --git a/k8s/jobs/desire.go b/k8s/jobs/desire.go index 0abd4b5d1..bdfdbc1cc 100644 --- a/k8s/jobs/desire.go +++ b/k8s/jobs/desire.go @@ -3,20 +3,15 @@ package jobs import ( "context" - "code.cloudfoundry.org/eirini-controller/k8s/utils/dockerutils" eiriniv1 "code.cloudfoundry.org/eirini-controller/pkg/apis/eirini/v1" - "code.cloudfoundry.org/eirini-controller/util" "code.cloudfoundry.org/lager" - "github.com/hashicorp/go-multierror" "github.com/pkg/errors" batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/client-go/kubernetes/scheme" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" ) //counterfeiter:generate . TaskToJobConverter @@ -24,7 +19,7 @@ import ( //counterfeiter:generate . SecretsClient type TaskToJobConverter interface { - Convert(*eiriniv1.Task, *corev1.Secret) *batchv1.Job + Convert(*eiriniv1.Task) *batchv1.Job } type JobCreator interface { @@ -61,88 +56,19 @@ func NewDesirer( func (d *Desirer) Desire(ctx context.Context, task *eiriniv1.Task) (*batchv1.Job, error) { logger := d.logger.Session("desire-task", lager.Data{"guid": task.Spec.GUID, "name": task.Name, "namespace": task.Namespace}) - var ( - err error - privateRegistrySecret *corev1.Secret - ) - - if imageInPrivateRegistry(task) { - privateRegistrySecret, err = d.createPrivateRegistrySecret(ctx, task.Namespace, task) - if err != nil { - return nil, errors.Wrap(err, "failed to create task secret") - } - } - - job := d.taskToJobConverter.Convert(task, privateRegistrySecret) + job := d.taskToJobConverter.Convert(task) job.Namespace = task.Namespace - if err = ctrl.SetControllerReference(task, job, d.scheme); err != nil { + if err := ctrl.SetControllerReference(task, job, d.scheme); err != nil { return nil, errors.Wrap(err, "failed to set controller reference") } - err = d.client.Create(ctx, job) - if err != nil { + if err := d.client.Create(ctx, job); err != nil { logger.Error("failed-to-create-job", err) - return nil, d.cleanupAndError(ctx, err, privateRegistrySecret) - } - - if privateRegistrySecret != nil { - originalSecret := privateRegistrySecret.DeepCopy() - - if err := controllerutil.SetOwnerReference(job, privateRegistrySecret, scheme.Scheme); err != nil { - return nil, errors.Wrap(err, "secret-client-set-owner-ref-failed") - } - - if err := d.client.Patch(ctx, privateRegistrySecret, client.MergeFrom(originalSecret)); err != nil { - return nil, errors.Wrap(err, "failed-to-set-secret-ownership") - } + return nil, err } return job, nil } - -func imageInPrivateRegistry(task *eiriniv1.Task) bool { - return task.Spec.PrivateRegistry != nil && task.Spec.PrivateRegistry.Username != "" && task.Spec.PrivateRegistry.Password != "" -} - -func (d *Desirer) createPrivateRegistrySecret(ctx context.Context, namespace string, task *eiriniv1.Task) (*corev1.Secret, error) { - secret := &corev1.Secret{} - - secret.GenerateName = PrivateRegistrySecretGenerateName - secret.Namespace = namespace - secret.Type = corev1.SecretTypeDockerConfigJson - - dockerConfig := dockerutils.NewDockerConfig( - util.ParseImageRegistryHost(task.Spec.Image), - task.Spec.PrivateRegistry.Username, - task.Spec.PrivateRegistry.Password, - ) - - dockerConfigJSON, err := dockerConfig.JSON() - if err != nil { - return nil, errors.Wrap(err, "failed-to-get-docker-config") - } - - secret.StringData = map[string]string{ - dockerutils.DockerConfigKey: dockerConfigJSON, - } - - err = d.client.Create(ctx, secret) - - return secret, err -} - -func (d *Desirer) cleanupAndError(ctx context.Context, jobCreationError error, privateRegistrySecret *corev1.Secret) error { - resultError := multierror.Append(nil, jobCreationError) - - if privateRegistrySecret != nil { - err := d.client.Delete(ctx, privateRegistrySecret) - if err != nil { - resultError = multierror.Append(resultError, errors.Wrap(err, "failed to cleanup registry secret")) - } - } - - return resultError -} diff --git a/k8s/jobs/desire_test.go b/k8s/jobs/desire_test.go index f99e42809..e8671108b 100644 --- a/k8s/jobs/desire_test.go +++ b/k8s/jobs/desire_test.go @@ -1,10 +1,6 @@ package jobs_test import ( - "context" - "encoding/base64" - "fmt" - "code.cloudfoundry.org/eirini-controller/k8s/jobs" "code.cloudfoundry.org/eirini-controller/k8s/jobs/jobsfakes" "code.cloudfoundry.org/eirini-controller/k8s/k8sfakes" @@ -17,7 +13,6 @@ import ( batchv1 "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - k8sclient "sigs.k8s.io/controller-runtime/pkg/client" ) var _ = Describe("Desire", func() { @@ -55,7 +50,10 @@ var _ = Describe("Desire", func() { Namespace: "app-namespace", }, Spec: eiriniv1.TaskSpec{ - Image: image, + Image: image, + ImagePullSecrets: []corev1.LocalObjectReference{{ + Name: "my-registry-secret", + }}, Command: []string{"/lifecycle/launch"}, AppName: "my-app", Name: "task-name", @@ -112,122 +110,4 @@ var _ = Describe("Desire", func() { It("sets the job namespace", func() { Expect(job.Namespace).To(Equal("app-namespace")) }) - - When("the task uses a private registry", func() { - var ( - createSecretError error - createJobError error - ) - - BeforeEach(func() { - createSecretError = nil - createJobError = nil - task.Spec.PrivateRegistry = &eiriniv1.PrivateRegistry{ - Username: "username", - Password: "password", - } - - client.CreateStub = func(_ context.Context, object k8sclient.Object, _ ...k8sclient.CreateOption) error { - secret, ok := object.(*corev1.Secret) - if ok { - if createSecretError != nil { - return createSecretError - } - secret.Name = secret.GenerateName + "1234" - } - - _, ok = object.(*batchv1.Job) - if ok { - return createJobError - } - - return nil - } - }) - - It("creates a secret with the registry credentials", func() { - Expect(client.CreateCallCount()).To(Equal(2)) - _, actualObject, _ := client.CreateArgsForCall(0) - actualSecret, ok := actualObject.(*corev1.Secret) - Expect(ok).To(BeTrue()) - - Expect(actualSecret.GenerateName).To(Equal("private-registry-")) - Expect(actualSecret.Type).To(Equal(corev1.SecretTypeDockerConfigJson)) - Expect(actualSecret.StringData).To( - HaveKeyWithValue( - ".dockerconfigjson", - fmt.Sprintf( - `{"auths":{"gcr.io":{"username":"username","password":"password","auth":"%s"}}}`, - base64.StdEncoding.EncodeToString([]byte("username:password")), - ), - ), - ) - }) - - It("converts the task using the private registry secret", func() { - _, actualSecret := taskToJobConverter.ConvertArgsForCall(0) - Expect(actualSecret.Name).To(Equal("private-registry-1234")) - }) - - It("sets the ownership of the secret to the job", func() { - Expect(client.PatchCallCount()).To(Equal(1)) - _, obj, _, _ := client.PatchArgsForCall(0) - Expect(obj).To(BeAssignableToTypeOf(&corev1.Secret{})) - - patchedSecret, ok := obj.(*corev1.Secret) - Expect(ok).To(BeTrue()) - - Expect(patchedSecret.OwnerReferences).To(HaveLen(1)) - Expect(patchedSecret.OwnerReferences[0].Kind).To(Equal("Job")) - Expect(patchedSecret.OwnerReferences[0].Name).To(Equal(job.Name)) - }) - - When("creating the secret fails", func() { - BeforeEach(func() { - createSecretError = errors.New("create-secret-err") - }) - - It("returns an error", func() { - Expect(desireErr).To(MatchError(ContainSubstring("create-secret-err"))) - }) - }) - - When("creating the job fails", func() { - BeforeEach(func() { - createJobError = errors.New("create-failed") - }) - - It("returns an error", func() { - Expect(desireErr).To(MatchError(ContainSubstring("create-failed"))) - }) - - It("deletes the secret", func() { - Expect(client.DeleteCallCount()).To(Equal(1)) - _, obj, _ := client.DeleteArgsForCall(0) - deletedSecret, ok := obj.(*corev1.Secret) - Expect(ok).To(BeTrue()) - Expect(deletedSecret.Name).To(Equal("private-registry-1234")) - }) - - When("deleting the secret fails", func() { - BeforeEach(func() { - client.DeleteReturns(errors.New("delete-secret-failed")) - }) - - It("returns a job creation error and a note that the secret is not cleaned up", func() { - Expect(desireErr).To(MatchError(And(ContainSubstring("create-failed"), ContainSubstring("delete-secret-failed")))) - }) - }) - }) - - When("setting the ownership of the secret fails", func() { - BeforeEach(func() { - client.PatchReturns(errors.New("potato")) - }) - - It("returns an error", func() { - Expect(desireErr).To(MatchError(ContainSubstring("potato"))) - }) - }) - }) }) diff --git a/k8s/jobs/jobsfakes/fake_task_to_job_converter.go b/k8s/jobs/jobsfakes/fake_task_to_job_converter.go index a6946ab9e..3c1d0f3ef 100644 --- a/k8s/jobs/jobsfakes/fake_task_to_job_converter.go +++ b/k8s/jobs/jobsfakes/fake_task_to_job_converter.go @@ -7,15 +7,13 @@ import ( "code.cloudfoundry.org/eirini-controller/k8s/jobs" v1a "code.cloudfoundry.org/eirini-controller/pkg/apis/eirini/v1" v1 "k8s.io/api/batch/v1" - v1b "k8s.io/api/core/v1" ) type FakeTaskToJobConverter struct { - ConvertStub func(*v1a.Task, *v1b.Secret) *v1.Job + ConvertStub func(*v1a.Task) *v1.Job convertMutex sync.RWMutex convertArgsForCall []struct { arg1 *v1a.Task - arg2 *v1b.Secret } convertReturns struct { result1 *v1.Job @@ -27,19 +25,18 @@ type FakeTaskToJobConverter struct { invocationsMutex sync.RWMutex } -func (fake *FakeTaskToJobConverter) Convert(arg1 *v1a.Task, arg2 *v1b.Secret) *v1.Job { +func (fake *FakeTaskToJobConverter) Convert(arg1 *v1a.Task) *v1.Job { fake.convertMutex.Lock() ret, specificReturn := fake.convertReturnsOnCall[len(fake.convertArgsForCall)] fake.convertArgsForCall = append(fake.convertArgsForCall, struct { arg1 *v1a.Task - arg2 *v1b.Secret - }{arg1, arg2}) + }{arg1}) stub := fake.ConvertStub fakeReturns := fake.convertReturns - fake.recordInvocation("Convert", []interface{}{arg1, arg2}) + fake.recordInvocation("Convert", []interface{}{arg1}) fake.convertMutex.Unlock() if stub != nil { - return stub(arg1, arg2) + return stub(arg1) } if specificReturn { return ret.result1 @@ -53,17 +50,17 @@ func (fake *FakeTaskToJobConverter) ConvertCallCount() int { return len(fake.convertArgsForCall) } -func (fake *FakeTaskToJobConverter) ConvertCalls(stub func(*v1a.Task, *v1b.Secret) *v1.Job) { +func (fake *FakeTaskToJobConverter) ConvertCalls(stub func(*v1a.Task) *v1.Job) { fake.convertMutex.Lock() defer fake.convertMutex.Unlock() fake.ConvertStub = stub } -func (fake *FakeTaskToJobConverter) ConvertArgsForCall(i int) (*v1a.Task, *v1b.Secret) { +func (fake *FakeTaskToJobConverter) ConvertArgsForCall(i int) *v1a.Task { fake.convertMutex.RLock() defer fake.convertMutex.RUnlock() argsForCall := fake.convertArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 + return argsForCall.arg1 } func (fake *FakeTaskToJobConverter) ConvertReturns(result1 *v1.Job) { diff --git a/k8s/jobs/task_to_job.go b/k8s/jobs/task_to_job.go index 81bd529c0..e5d4242d1 100644 --- a/k8s/jobs/task_to_job.go +++ b/k8s/jobs/task_to_job.go @@ -34,7 +34,7 @@ func NewTaskToJobConverter( } } -func (m *Converter) Convert(task *eiriniv1.Task, privateRegistrySecret *corev1.Secret) *batch.Job { +func (m *Converter) Convert(task *eiriniv1.Task) *batch.Job { job := m.toJob(task) job.Spec.Template.Spec.ServiceAccountName = m.serviceAccountName job.Labels[LabelSourceType] = TaskSourceType @@ -66,16 +66,8 @@ func (m *Converter) Convert(task *eiriniv1.Task, privateRegistrySecret *corev1.S }, } - job.Spec.Template.Spec.ImagePullSecrets = []corev1.LocalObjectReference{ - { - Name: m.registrySecretName, - }, - } - - if privateRegistrySecret != nil { - job.Spec.Template.Spec.ImagePullSecrets = append(job.Spec.Template.Spec.ImagePullSecrets, - corev1.LocalObjectReference{Name: privateRegistrySecret.Name}) - } + job.Spec.Template.Spec.ImagePullSecrets = []corev1.LocalObjectReference{{Name: m.registrySecretName}} + job.Spec.Template.Spec.ImagePullSecrets = append(job.Spec.Template.Spec.ImagePullSecrets, task.Spec.ImagePullSecrets...) job.Spec.Template.Spec.Containers = containers diff --git a/k8s/jobs/task_to_job_test.go b/k8s/jobs/task_to_job_test.go index d0aa9a848..a5e5a6fc8 100644 --- a/k8s/jobs/task_to_job_test.go +++ b/k8s/jobs/task_to_job_test.go @@ -12,7 +12,6 @@ import ( batch "k8s.io/api/batch/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) var _ = Describe("TaskToJob", func() { @@ -25,7 +24,6 @@ var _ = Describe("TaskToJob", func() { var ( job *batch.Job - privateRegistrySecret *corev1.Secret task *eiriniv1.Task allowAutomountServiceAccountToken bool ) @@ -55,7 +53,6 @@ var _ = Describe("TaskToJob", func() { BeforeEach(func() { allowAutomountServiceAccountToken = false - privateRegistrySecret = nil task = &eiriniv1.Task{ Spec: eiriniv1.TaskSpec{ @@ -80,7 +77,7 @@ var _ = Describe("TaskToJob", func() { }) JustBeforeEach(func() { - job = jobs.NewTaskToJobConverter(serviceAccount, registrySecret, allowAutomountServiceAccountToken).Convert(task, privateRegistrySecret) + job = jobs.NewTaskToJobConverter(serviceAccount, registrySecret, allowAutomountServiceAccountToken).Convert(task) }) It("returns a job for the task with the correct attributes", func() { @@ -230,19 +227,15 @@ var _ = Describe("TaskToJob", func() { }) }) - When("the task uses a private registry", func() { + When("the task supplies an addition registry secret", func() { BeforeEach(func() { - privateRegistrySecret = &corev1.Secret{ - ObjectMeta: v1.ObjectMeta{ - Name: "the-private-registry-secret", - }, - } + task.Spec.ImagePullSecrets = []corev1.LocalObjectReference{{Name: "my-registry-secret"}} }) - It("creates a secret reference with the private registry credentials", func() { + It("appends the extra image pull secret on the pod spec", func() { Expect(job.Spec.Template.Spec.ImagePullSecrets).To(ConsistOf( corev1.LocalObjectReference{Name: "registry-secret"}, - corev1.LocalObjectReference{Name: "the-private-registry-secret"}, + corev1.LocalObjectReference{Name: "my-registry-secret"}, )) }) }) diff --git a/k8s/reconciler/task_test.go b/k8s/reconciler/task_test.go index 4aa2aa70d..7e1387986 100644 --- a/k8s/reconciler/task_test.go +++ b/k8s/reconciler/task_test.go @@ -306,24 +306,6 @@ var _ = Describe("Task", func() { }) }) - When("there is a private registry set", func() { - BeforeEach(func() { - getJobErr = k8serrors.NewNotFound(schema.GroupResource{}, "not found") - task.Spec.PrivateRegistry = &eiriniv1.PrivateRegistry{ - Username: "admin", - Password: "p4ssw0rd", - } - }) - - It("passes the private registry details to the desirer", func() { - Expect(desirer.DesireCallCount()).To(Equal(1)) - _, actualTask := desirer.DesireArgsForCall(0) - Expect(actualTask.Spec.PrivateRegistry).ToNot(BeNil()) - Expect(actualTask.Spec.PrivateRegistry.Username).To(Equal("admin")) - Expect(actualTask.Spec.PrivateRegistry.Password).To(Equal("p4ssw0rd")) - }) - }) - When("the job has already been desired", func() { BeforeEach(func() { getJobErr = nil diff --git a/pkg/apis/eirini/v1/task.go b/pkg/apis/eirini/v1/task.go index 19cdb93b7..7af96c2c4 100644 --- a/pkg/apis/eirini/v1/task.go +++ b/pkg/apis/eirini/v1/task.go @@ -26,8 +26,8 @@ type TaskSpec struct { GUID string `json:"GUID"` Name string `json:"name"` // +kubebuilder:validation:Required - Image string `json:"image"` - PrivateRegistry *PrivateRegistry `json:"privateRegistry,omitempty"` + Image string `json:"image"` + ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"` // deprecated: Env is deprecated. Use Environment instead Env map[string]string `json:"env,omitempty"` Environment []corev1.EnvVar `json:"environment,omitempty"` diff --git a/pkg/apis/eirini/v1/zz_generated.deepcopy.go b/pkg/apis/eirini/v1/zz_generated.deepcopy.go index 28b3489d1..576d6daff 100644 --- a/pkg/apis/eirini/v1/zz_generated.deepcopy.go +++ b/pkg/apis/eirini/v1/zz_generated.deepcopy.go @@ -299,10 +299,10 @@ func (in *TaskList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TaskSpec) DeepCopyInto(out *TaskSpec) { *out = *in - if in.PrivateRegistry != nil { - in, out := &in.PrivateRegistry, &out.PrivateRegistry - *out = new(PrivateRegistry) - **out = **in + if in.ImagePullSecrets != nil { + in, out := &in.ImagePullSecrets, &out.ImagePullSecrets + *out = make([]corev1.LocalObjectReference, len(*in)) + copy(*out, *in) } if in.Env != nil { in, out := &in.Env, &out.Env diff --git a/tests/eats/tasks_crd_test.go b/tests/eats/tasks_crd_test.go index 8833cd3b2..7b5a2dfe3 100644 --- a/tests/eats/tasks_crd_test.go +++ b/tests/eats/tasks_crd_test.go @@ -130,10 +130,8 @@ var _ = Describe("Tasks CRD [needs-logs-for: eirini-controller]", func() { When("the task image lives in a private registry", func() { BeforeEach(func() { task.Spec.Image = "eiriniuser/notdora:latest" - task.Spec.PrivateRegistry = &eiriniv1.PrivateRegistry{ - Username: "eiriniuser", - Password: tests.GetEiriniDockerHubPassword(), - } + secret := tests.CreateRegistrySecret(ctx, fixture.Clientset, "private-registry-secret", fixture.Namespace, "eiriniuser", tests.GetEiriniDockerHubPassword(), task.Spec.Image) + task.Spec.ImagePullSecrets = []corev1.LocalObjectReference{{Name: secret.Name}} port = 8888 }) diff --git a/tests/integration/k8s/jobs/desire_test.go b/tests/integration/k8s/jobs/desire_test.go index 5b11aa0a4..c229a4e96 100644 --- a/tests/integration/k8s/jobs/desire_test.go +++ b/tests/integration/k8s/jobs/desire_test.go @@ -99,12 +99,10 @@ var _ = Describe("Task Desirer", func() { When("the task image lives in a private registry", func() { BeforeEach(func() { + secret := tests.CreateRegistrySecret(ctx, fixture.Clientset, "private-registry-secret", fixture.Namespace, "eiriniuser", tests.GetEiriniDockerHubPassword(), task.Spec.Image) + task.Spec.ImagePullSecrets = []corev1.LocalObjectReference{{Name: secret.Name}} task.Spec.Image = "eiriniuser/notdora:latest" task.Spec.Command = []string{"/bin/echo", "hello"} - task.Spec.PrivateRegistry = &eiriniv1.PrivateRegistry{ - Username: "eiriniuser", - Password: tests.GetEiriniDockerHubPassword(), - } }) It("runs and completes the job", func() { @@ -121,47 +119,6 @@ var _ = Describe("Task Desirer", func() { })), ) }) - - It("creates a ImagePullSecret with the credentials", func() { - registrySecretName := integration.GetRegistrySecretName(fixture.Clientset, fixture.Namespace, taskGUID, jobs.PrivateRegistrySecretGenerateName) - - getSecret := func() (*corev1.Secret, error) { - return fixture.Clientset. - CoreV1(). - Secrets(fixture.Namespace). - Get(context.Background(), registrySecretName, metav1.GetOptions{}) - } - - secret, err := getSecret() - - Expect(err).NotTo(HaveOccurred()) - - By("creating the secret", func() { - Expect(secret.Name).To(ContainSubstring(jobs.PrivateRegistrySecretGenerateName)) - Expect(secret.Type).To(Equal(corev1.SecretTypeDockerConfigJson)) - Expect(secret.Data).To(HaveKey(".dockerconfigjson")) - }) - - By("setting the owner reference on the secret", func() { - allJobs := integration.ListJobs(fixture.Clientset, fixture.Namespace, taskGUID)() - job := allJobs[0] - - var ownerRefs []metav1.OwnerReference - Eventually(func() []metav1.OwnerReference { - s, err := getSecret() - if err != nil { - return nil - } - - ownerRefs = s.OwnerReferences - - return ownerRefs - }).Should(HaveLen(1)) - - Expect(ownerRefs[0].Name).To(Equal(job.Name)) - Expect(ownerRefs[0].UID).To(Equal(job.UID)) - }) - }) }) }) diff --git a/tests/k8s.go b/tests/k8s.go index 27cbfbf0d..7bd05bf7c 100644 --- a/tests/k8s.go +++ b/tests/k8s.go @@ -9,6 +9,8 @@ import ( "time" "code.cloudfoundry.org/eirini-controller/k8s/stset" + "code.cloudfoundry.org/eirini-controller/k8s/utils/dockerutils" + "code.cloudfoundry.org/eirini-controller/util" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" @@ -145,3 +147,23 @@ func RequestService(namespace, serviceName string, port int32, requestPath strin return resp } + +func CreateRegistrySecret(ctx context.Context, clientset kubernetes.Interface, name, namespace, username, password, forImage string) *corev1.Secret { + dockerConfig := dockerutils.NewDockerConfig(util.ParseImageRegistryHost(forImage), "eiriniuser", GetEiriniDockerHubPassword()) + dockerConfigJson, err := dockerConfig.JSON() + ExpectWithOffset(1, err).NotTo(HaveOccurred()) + + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: "private-registry-secret", + }, + StringData: map[string]string{ + dockerutils.DockerConfigKey: dockerConfigJson, + }, + Type: corev1.SecretTypeDockerConfigJson, + } + secret, err = clientset.CoreV1().Secrets(namespace).Create(ctx, secret, metav1.CreateOptions{}) + ExpectWithOffset(1, err).NotTo(HaveOccurred()) + + return secret +}