src: use common functionality for docker cred retrieval (#756)

* Use common functionality for docker cred retrieval

Signed-off-by: Matej Vasek <mvasek@redhat.com>

* fixup: docker auth secret for tekton pipeline

Signed-off-by: Matej Vasek <mvasek@redhat.com>

* fixup: style

Signed-off-by: Matej Vasek <mvasek@redhat.com>
This commit is contained in:
Matej Vasek 2022-01-13 12:52:12 +01:00 committed by GitHub
parent cb719ff564
commit 15d617f99d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 36 additions and 82 deletions

View File

@ -20,7 +20,6 @@ import (
"knative.dev/kn-plugin-func/docker" "knative.dev/kn-plugin-func/docker"
"knative.dev/kn-plugin-func/docker/creds" "knative.dev/kn-plugin-func/docker/creds"
"knative.dev/kn-plugin-func/knative" "knative.dev/kn-plugin-func/knative"
"knative.dev/kn-plugin-func/pipelines"
"knative.dev/kn-plugin-func/pipelines/tekton" "knative.dev/kn-plugin-func/pipelines/tekton"
"knative.dev/kn-plugin-func/progress" "knative.dev/kn-plugin-func/progress"
) )
@ -37,11 +36,13 @@ func newDeployClient(cfg deployConfig) (*fn.Client, error) {
pusher *docker.Pusher pusher *docker.Pusher
err error err error
) )
credentialsProvider := creds.NewCredentialsProvider(
creds.WithPromptForCredentials(newPromptForCredentials()),
creds.WithPromptForCredentialStore(newPromptForCredentialStore()),
creds.WithTransport(cfg.Transport))
if cfg.Push { if cfg.Push {
credentialsProvider := creds.NewCredentialsProvider(
creds.WithPromptForCredentials(newPromptForCredentials()),
creds.WithPromptForCredentialStore(newPromptForCredentialStore()),
creds.WithTransport(cfg.Transport))
pusher, err = docker.NewPusher( pusher, err = docker.NewPusher(
docker.WithCredentialsProvider(credentialsProvider), docker.WithCredentialsProvider(credentialsProvider),
docker.WithProgressListener(listener), docker.WithProgressListener(listener),
@ -60,7 +61,7 @@ func newDeployClient(cfg deployConfig) (*fn.Client, error) {
pipelinesProvider, err := tekton.NewPipelinesProvider( pipelinesProvider, err := tekton.NewPipelinesProvider(
tekton.WithNamespace(cfg.Namespace), tekton.WithNamespace(cfg.Namespace),
tekton.WithProgressListener(listener), tekton.WithProgressListener(listener),
tekton.WithPromptForContainerRegistryCredentials(newPromptForPipelineRegistryCredentials())) tekton.WithCredentialsProvider(credentialsProvider))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -287,44 +288,6 @@ func newPromptForCredentials() func(registry string) (docker.Credentials, error)
} }
} }
func newPromptForPipelineRegistryCredentials() pipelines.ContainerRegistryCredentialsCallback {
return func() (pipelines.ContainerRegistryCredentials, error) {
var result pipelines.ContainerRegistryCredentials
var qs = []*survey.Question{
{
Name: "server",
Prompt: &survey.Input{
Message: "Server:",
Default: "https://index.docker.io/v1/",
},
Validate: survey.Required,
},
{
Name: "username",
Prompt: &survey.Input{
Message: "Username:",
},
Validate: survey.Required,
},
{
Name: "password",
Prompt: &survey.Password{
Message: "Password:",
},
Validate: survey.Required,
},
}
fmt.Printf("Please provide credentials for the image registry used by Pipeline.\n")
err := survey.Ask(qs, &result)
if err != nil {
return pipelines.ContainerRegistryCredentials{}, err
}
return result, nil
}
}
func newPromptForCredentialStore() creds.ChooseCredentialHelperCallback { func newPromptForCredentialStore() creds.ChooseCredentialHelperCallback {
return func(availableHelpers []string) (string, error) { return func(availableHelpers []string) (string, error) {
if len(availableHelpers) < 1 { if len(availableHelpers) < 1 {

View File

@ -12,13 +12,11 @@ import (
"net/http" "net/http"
"os" "os"
"regexp" "regexp"
"strings"
"github.com/docker/docker/client"
fn "knative.dev/kn-plugin-func" fn "knative.dev/kn-plugin-func"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/client"
"github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/name"
v1 "github.com/google/go-containerregistry/pkg/v1" v1 "github.com/google/go-containerregistry/pkg/v1"
@ -111,18 +109,12 @@ func NewPusher(opts ...Opt) (*Pusher, error) {
return result, nil return result, nil
} }
func GetRegistry(image_url string) (string, error) { func GetRegistry(img string) (string, error) {
var registry string ref, err := name.ParseReference(img, name.WeakValidation)
parts := strings.Split(image_url, "/") if err != nil {
switch { return "", err
case len(parts) == 2:
registry = fn.DefaultRegistry
case len(parts) >= 3:
registry = parts[0]
default:
return "", fmt.Errorf("failed to parse image name: %q", image_url)
} }
registry := ref.Context().RegistryStr()
return registry, nil return registry, nil
} }

View File

@ -45,18 +45,13 @@ func TestGetRegistry(t *testing.T) {
{ {
name: "default registry", name: "default registry",
arg: "docker.io/mysamplefunc:latest", arg: "docker.io/mysamplefunc:latest",
want: "docker.io", want: "index.docker.io",
}, },
{ {
name: "long-form nested url", name: "long-form nested url",
arg: "myregistry.io/myorg/myuser/myfunctions/mysamplefunc:latest", arg: "myregistry.io/myorg/myuser/myfunctions/mysamplefunc:latest",
want: "myregistry.io", want: "myregistry.io",
}, },
{
name: "invalid url",
arg: "myregistry.io-mysamplefunc:latest",
want: "",
},
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {

1
pipelines/init.go Normal file
View File

@ -0,0 +1 @@
package pipelines

View File

@ -1,9 +0,0 @@
package pipelines
type ContainerRegistryCredentialsCallback func() (ContainerRegistryCredentials, error)
type ContainerRegistryCredentials struct {
Username string
Password string
Server string
}

View File

@ -5,6 +5,9 @@ import (
"fmt" "fmt"
"sync" "sync"
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name"
"github.com/tektoncd/cli/pkg/pipelinerun" "github.com/tektoncd/cli/pkg/pipelinerun"
"github.com/tektoncd/cli/pkg/taskrun" "github.com/tektoncd/cli/pkg/taskrun"
"github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
@ -14,9 +17,9 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fn "knative.dev/kn-plugin-func" fn "knative.dev/kn-plugin-func"
"knative.dev/kn-plugin-func/docker"
"knative.dev/kn-plugin-func/k8s" "knative.dev/kn-plugin-func/k8s"
"knative.dev/kn-plugin-func/knative" "knative.dev/kn-plugin-func/knative"
"knative.dev/kn-plugin-func/pipelines"
"knative.dev/pkg/apis" "knative.dev/pkg/apis"
) )
@ -25,10 +28,10 @@ type Opt func(*PipelinesProvider) error
type PipelinesProvider struct { type PipelinesProvider struct {
// namespace with which to override that set on the default configuration (such as the ~/.kube/config). // namespace with which to override that set on the default configuration (such as the ~/.kube/config).
// If left blank, pipeline creation/run will commence to the configured namespace. // If left blank, pipeline creation/run will commence to the configured namespace.
namespace string namespace string
Verbose bool Verbose bool
progressListener fn.ProgressListener progressListener fn.ProgressListener
containerRegistryCredentialsCallback pipelines.ContainerRegistryCredentialsCallback credentialsProvider docker.CredentialsProvider
} }
func WithNamespace(namespace string) Opt { func WithNamespace(namespace string) Opt {
@ -49,9 +52,9 @@ func WithProgressListener(pl fn.ProgressListener) Opt {
} }
} }
func WithPromptForContainerRegistryCredentials(cbk pipelines.ContainerRegistryCredentialsCallback) Opt { func WithCredentialsProvider(credentialsProvider docker.CredentialsProvider) Opt {
return func(pp *PipelinesProvider) error { return func(pp *PipelinesProvider) error {
pp.containerRegistryCredentialsCallback = cbk pp.credentialsProvider = credentialsProvider
return nil return nil
} }
} }
@ -97,16 +100,25 @@ func (pp *PipelinesProvider) Run(ctx context.Context, f fn.Function) error {
} }
} }
registry, err := docker.GetRegistry(f.Image)
if err != nil {
return err
}
_, err = k8s.GetSecret(ctx, getPipelineSecretName(f), pp.namespace) _, err = k8s.GetSecret(ctx, getPipelineSecretName(f), pp.namespace)
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
pp.progressListener.Stopping() pp.progressListener.Stopping()
creds, err := pp.containerRegistryCredentialsCallback() creds, err := pp.credentialsProvider(ctx, registry)
if err != nil { if err != nil {
return err return err
} }
pp.progressListener.Increment("Creating Pipeline resources") pp.progressListener.Increment("Creating Pipeline resources")
err = k8s.CreateDockerRegistrySecret(ctx, getPipelineSecretName(f), pp.namespace, creds.Username, creds.Password, creds.Server) if registry == name.DefaultRegistry {
registry = authn.DefaultAuthKey
}
err = k8s.CreateDockerRegistrySecret(ctx, getPipelineSecretName(f), pp.namespace, creds.Username, creds.Password, registry)
if err != nil { if err != nil {
return err return err
} }