mirror of https://github.com/knative/func.git
151 lines
5.5 KiB
Go
151 lines
5.5 KiB
Go
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
|
|
"knative.dev/func/cmd/prompt"
|
|
"knative.dev/func/pkg/builders/buildpacks"
|
|
"knative.dev/func/pkg/config"
|
|
"knative.dev/func/pkg/docker"
|
|
"knative.dev/func/pkg/docker/creds"
|
|
fn "knative.dev/func/pkg/functions"
|
|
fnhttp "knative.dev/func/pkg/http"
|
|
"knative.dev/func/pkg/k8s"
|
|
"knative.dev/func/pkg/knative"
|
|
"knative.dev/func/pkg/pipelines/tekton"
|
|
)
|
|
|
|
// ClientConfig settings for use with NewClient
|
|
// These are the minimum settings necessary to create the default client
|
|
// instance which has most subsystems initialized.
|
|
type ClientConfig struct {
|
|
// Verbose logging. By default, logging output is kept to the bare minimum.
|
|
// Use this flag to configure verbose logging throughout.
|
|
Verbose bool
|
|
|
|
// Allow insecure server connections when using SSL
|
|
InsecureSkipVerify bool
|
|
}
|
|
|
|
// ClientFactory defines a constructor which assists in the creation of a Client
|
|
// for use by commands.
|
|
// See the NewClient constructor which is the fully populated ClientFactory used
|
|
// by commands by default.
|
|
// See NewClientFactory which constructs a minimal ClientFactory for use
|
|
// during testing.
|
|
type ClientFactory func(ClientConfig, ...fn.Option) (*fn.Client, func())
|
|
|
|
// NewTestClient returns a client factory which will ignore options used,
|
|
// instead using those provided when creating the factory. This allows
|
|
// for tests to create an entirely default client but with N mocks.
|
|
func NewTestClient(options ...fn.Option) ClientFactory {
|
|
return func(_ ClientConfig, _ ...fn.Option) (*fn.Client, func()) {
|
|
return fn.New(options...), func() {}
|
|
}
|
|
}
|
|
|
|
// NewClient constructs an fn.Client with the majority of
|
|
// the concrete implementations set. Provide additional Options to this constructor
|
|
// to override or augment as needed, or override the ClientFactory passed to
|
|
// commands entirely to mock for testing. Note the returned cleanup function.
|
|
// 'Namespace' is optional. If not provided (see DefaultNamespace commentary),
|
|
// the currently configured is used.
|
|
// 'Verbose' indicates the system should write out a higher amount of logging.
|
|
func NewClient(cfg ClientConfig, options ...fn.Option) (*fn.Client, func()) {
|
|
var (
|
|
t = newTransport(cfg.InsecureSkipVerify) // may provide a custom impl which proxies
|
|
c = newCredentialsProvider(config.Dir(), t) // for accessing registries
|
|
d = newKnativeDeployer(cfg.Verbose)
|
|
pp = newTektonPipelinesProvider(c, cfg.Verbose)
|
|
o = []fn.Option{ // standard (shared) options for all commands
|
|
fn.WithVerbose(cfg.Verbose),
|
|
fn.WithTransport(t),
|
|
fn.WithRepositoriesPath(config.RepositoriesPath()),
|
|
fn.WithBuilder(buildpacks.NewBuilder(buildpacks.WithVerbose(cfg.Verbose))),
|
|
fn.WithRemover(knative.NewRemover(cfg.Verbose)),
|
|
fn.WithDescriber(knative.NewDescriber(cfg.Verbose)),
|
|
fn.WithLister(knative.NewLister(cfg.Verbose)),
|
|
fn.WithDeployer(d),
|
|
fn.WithPipelinesProvider(pp),
|
|
fn.WithPusher(docker.NewPusher(
|
|
docker.WithCredentialsProvider(c),
|
|
docker.WithTransport(t),
|
|
docker.WithVerbose(cfg.Verbose))),
|
|
}
|
|
)
|
|
|
|
// Client is constructed with standard options plus any additional options
|
|
// which either augment or override the defaults.
|
|
client := fn.New(append(o, options...)...)
|
|
|
|
// A deferrable cleanup function which is used to perform any cleanup, such
|
|
// as closing the transport
|
|
cleanup := func() {
|
|
if err := t.Close(); err != nil {
|
|
fmt.Fprintf(os.Stderr, "error closing http transport. %v", err)
|
|
}
|
|
}
|
|
|
|
return client, cleanup
|
|
}
|
|
|
|
// newTransport returns a transport with cluster-flavor-specific variations
|
|
// which take advantage of additional features offered by cluster variants.
|
|
func newTransport(insecureSkipVerify bool) fnhttp.RoundTripCloser {
|
|
return fnhttp.NewRoundTripper(fnhttp.WithInsecureSkipVerify(insecureSkipVerify), fnhttp.WithOpenShiftServiceCA())
|
|
}
|
|
|
|
// newCredentialsProvider returns a credentials provider which possibly
|
|
// has cluster-flavor specific additional credential loaders to take advantage
|
|
// of features or configuration nuances of cluster variants.
|
|
func newCredentialsProvider(configPath string, t http.RoundTripper) docker.CredentialsProvider {
|
|
options := []creds.Opt{
|
|
creds.WithPromptForCredentials(prompt.NewPromptForCredentials(os.Stdin, os.Stdout, os.Stderr)),
|
|
creds.WithPromptForCredentialStore(prompt.NewPromptForCredentialStore()),
|
|
creds.WithTransport(t),
|
|
creds.WithAdditionalCredentialLoaders(k8s.GetOpenShiftDockerCredentialLoaders()...),
|
|
}
|
|
|
|
// Other cluster variants can be supported here
|
|
return creds.NewCredentialsProvider(configPath, options...)
|
|
}
|
|
|
|
func newTektonPipelinesProvider(creds docker.CredentialsProvider, verbose bool) *tekton.PipelinesProvider {
|
|
options := []tekton.Opt{
|
|
tekton.WithCredentialsProvider(creds),
|
|
tekton.WithVerbose(verbose),
|
|
tekton.WithPipelineDecorator(deployDecorator{}),
|
|
}
|
|
|
|
return tekton.NewPipelinesProvider(options...)
|
|
}
|
|
|
|
func newKnativeDeployer(verbose bool) fn.Deployer {
|
|
options := []knative.DeployerOpt{
|
|
knative.WithDeployerVerbose(verbose),
|
|
knative.WithDeployerDecorator(deployDecorator{}),
|
|
}
|
|
|
|
return knative.NewDeployer(options...)
|
|
}
|
|
|
|
type deployDecorator struct {
|
|
oshDec k8s.OpenshiftMetadataDecorator
|
|
}
|
|
|
|
func (d deployDecorator) UpdateAnnotations(function fn.Function, annotations map[string]string) map[string]string {
|
|
if k8s.IsOpenShift() {
|
|
return d.oshDec.UpdateAnnotations(function, annotations)
|
|
}
|
|
return annotations
|
|
}
|
|
|
|
func (d deployDecorator) UpdateLabels(function fn.Function, labels map[string]string) map[string]string {
|
|
if k8s.IsOpenShift() {
|
|
return d.oshDec.UpdateLabels(function, labels)
|
|
}
|
|
return labels
|
|
}
|