mirror of https://github.com/knative/func.git
173 lines
6.3 KiB
Go
173 lines
6.3 KiB
Go
package cmd
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
|
|
fn "knative.dev/kn-plugin-func"
|
|
"knative.dev/kn-plugin-func/buildpacks"
|
|
"knative.dev/kn-plugin-func/docker"
|
|
"knative.dev/kn-plugin-func/docker/creds"
|
|
fnhttp "knative.dev/kn-plugin-func/http"
|
|
"knative.dev/kn-plugin-func/knative"
|
|
"knative.dev/kn-plugin-func/openshift"
|
|
"knative.dev/kn-plugin-func/pipelines/tekton"
|
|
"knative.dev/kn-plugin-func/progress"
|
|
)
|
|
|
|
// 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 {
|
|
// Namespace in the remote cluster to use for any client commands which
|
|
// touch the remote. Optional. Empty namespace indicates the namespace
|
|
// currently configured in the client's connection should be used.
|
|
Namespace string
|
|
|
|
// 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())
|
|
|
|
// NewClientFactory enables simple instantiation of an fn.Client, such as
|
|
// for mocking during tests or for minimal api usage.
|
|
// Given is a minimal Client constructor, Returned is full ClientFactory
|
|
// with the aspects of normal (full) Client construction (namespace, verbosity
|
|
// level, additional options and the returned cleanup function) ignored.
|
|
func NewClientFactory(n func() *fn.Client) ClientFactory {
|
|
return func(_ ClientConfig, _ ...fn.Option) (*fn.Client, func()) {
|
|
return n(), 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.
|
|
// Example:
|
|
//
|
|
// client, done := NewClient("",false)
|
|
// defer done()
|
|
func NewClient(cfg ClientConfig, options ...fn.Option) (*fn.Client, func()) {
|
|
var (
|
|
p = progress.New(cfg.Verbose) // updates the CLI
|
|
t = newTransport(cfg.InsecureSkipVerify) // may provide a custom impl which proxies
|
|
c = newCredentialsProvider(t) // for accessing registries
|
|
d = newKnativeDeployer(cfg.Namespace, cfg.Verbose)
|
|
pp = newTektonPipelinesProvider(cfg.Namespace, p, c, cfg.Verbose)
|
|
o = []fn.Option{ // standard (shared) options for all commands
|
|
fn.WithVerbose(cfg.Verbose),
|
|
fn.WithProgressListener(p),
|
|
fn.WithTransport(t),
|
|
fn.WithBuilder(buildpacks.NewBuilder(buildpacks.WithVerbose(cfg.Verbose))),
|
|
fn.WithRemover(knative.NewRemover(cfg.Namespace, cfg.Verbose)),
|
|
fn.WithDescriber(knative.NewDescriber(cfg.Namespace, cfg.Verbose)),
|
|
fn.WithLister(knative.NewLister(cfg.Namespace, cfg.Verbose)),
|
|
fn.WithRunner(docker.NewRunner(cfg.Verbose)),
|
|
fn.WithDeployer(d),
|
|
fn.WithPipelinesProvider(pp),
|
|
fn.WithPusher(docker.NewPusher(
|
|
docker.WithCredentialsProvider(c),
|
|
docker.WithProgressListener(p),
|
|
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 {
|
|
if openshift.IsOpenShift() {
|
|
return fnhttp.NewRoundTripper(fnhttp.WithInsecureSkipVerify(insecureSkipVerify), openshift.WithOpenShiftServiceCA())
|
|
}
|
|
|
|
// Other cluster variants ...
|
|
|
|
return fnhttp.NewRoundTripper(fnhttp.WithInsecureSkipVerify(insecureSkipVerify)) // Default (vanilla k8s)
|
|
}
|
|
|
|
// 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(t http.RoundTripper) docker.CredentialsProvider {
|
|
options := []creds.Opt{
|
|
creds.WithPromptForCredentials(newPromptForCredentials(os.Stdin, os.Stdout, os.Stderr)),
|
|
creds.WithPromptForCredentialStore(newPromptForCredentialStore()),
|
|
creds.WithTransport(t),
|
|
}
|
|
// The OpenShift variant has additional ways to load credentials
|
|
if openshift.IsOpenShift() {
|
|
options = append(options,
|
|
creds.WithAdditionalCredentialLoaders(openshift.GetDockerCredentialLoaders()...))
|
|
}
|
|
// Other cluster variants can be supported here
|
|
return creds.NewCredentialsProvider(options...)
|
|
}
|
|
|
|
func newTektonPipelinesProvider(namespace string, progress *progress.Bar, creds docker.CredentialsProvider, verbose bool) *tekton.PipelinesProvider {
|
|
options := []tekton.Opt{
|
|
tekton.WithNamespace(namespace),
|
|
tekton.WithProgressListener(progress),
|
|
tekton.WithCredentialsProvider(creds),
|
|
tekton.WithVerbose(verbose),
|
|
}
|
|
|
|
if openshift.IsOpenShift() {
|
|
options = append(options, tekton.WithPipelineDecorator(openshift.OpenshiftMetadataDecorator{}))
|
|
}
|
|
|
|
return tekton.NewPipelinesProvider(options...)
|
|
}
|
|
|
|
func newKnativeDeployer(namespace string, verbose bool) fn.Deployer {
|
|
options := []knative.DeployerOpt{
|
|
knative.WithDeployerNamespace(namespace),
|
|
knative.WithDeployerVerbose(verbose),
|
|
}
|
|
|
|
if openshift.IsOpenShift() {
|
|
options = append(options, knative.WithDeployerDecorator(openshift.OpenshiftMetadataDecorator{}))
|
|
}
|
|
|
|
return knative.NewDeployer(options...)
|
|
}
|
|
|
|
func GetDefaultRegistry() string {
|
|
switch {
|
|
case openshift.IsOpenShift():
|
|
return openshift.GetDefaultRegistry()
|
|
default:
|
|
return ""
|
|
}
|
|
}
|